8295159: DSO created with -ffast-math breaks Java floating-point arithmetic
Reviewed-by: ihse, dholmes, stuefe
This commit is contained in:
parent
c099cf53f2
commit
df599dbb9b
@ -851,6 +851,7 @@ ifeq ($(call isTargetOs, linux), true)
|
|||||||
BUILD_TEST_exeinvoke_exeinvoke.c_OPTIMIZATION := NONE
|
BUILD_TEST_exeinvoke_exeinvoke.c_OPTIMIZATION := NONE
|
||||||
BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeFPRegs := -ldl
|
BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeFPRegs := -ldl
|
||||||
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libAsyncGetCallTraceTest := -ldl
|
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libAsyncGetCallTraceTest := -ldl
|
||||||
|
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libfast-math := -ffast-math
|
||||||
else
|
else
|
||||||
BUILD_HOTSPOT_JTREG_EXCLUDE += libtest-rw.c libtest-rwx.c \
|
BUILD_HOTSPOT_JTREG_EXCLUDE += libtest-rw.c libtest-rwx.c \
|
||||||
exeinvoke.c exestack-gap.c exestack-tls.c libAsyncGetCallTraceTest.cpp
|
exeinvoke.c exestack-gap.c exestack-tls.c libAsyncGetCallTraceTest.cpp
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
# include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
|
# include <fenv.h>
|
||||||
# include <inttypes.h>
|
# include <inttypes.h>
|
||||||
# include <poll.h>
|
# include <poll.h>
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
@ -975,6 +976,41 @@ bool os::dll_address_to_library_name(address addr, char* buf,
|
|||||||
// in case of error it checks if .dll/.so was built for the
|
// in case of error it checks if .dll/.so was built for the
|
||||||
// same architecture as Hotspot is running on
|
// same architecture as Hotspot is running on
|
||||||
|
|
||||||
|
void *os::Bsd::dlopen_helper(const char *filename, int mode) {
|
||||||
|
#ifndef IA32
|
||||||
|
// Save and restore the floating-point environment around dlopen().
|
||||||
|
// There are known cases where global library initialization sets
|
||||||
|
// FPU flags that affect computation accuracy, for example, enabling
|
||||||
|
// Flush-To-Zero and Denormals-Are-Zero. Do not let those libraries
|
||||||
|
// break Java arithmetic. Unfortunately, this might affect libraries
|
||||||
|
// that might depend on these FPU features for performance and/or
|
||||||
|
// numerical "accuracy", but we need to protect Java semantics first
|
||||||
|
// and foremost. See JDK-8295159.
|
||||||
|
|
||||||
|
// This workaround is ineffective on IA32 systems because the MXCSR
|
||||||
|
// register (which controls flush-to-zero mode) is not stored in the
|
||||||
|
// legacy fenv.
|
||||||
|
|
||||||
|
fenv_t default_fenv;
|
||||||
|
int rtn = fegetenv(&default_fenv);
|
||||||
|
assert(rtn == 0, "fegetenv must succeed");
|
||||||
|
#endif // IA32
|
||||||
|
|
||||||
|
void * result= ::dlopen(filename, RTLD_LAZY);
|
||||||
|
|
||||||
|
#ifndef IA32
|
||||||
|
if (result != nullptr && ! IEEE_subnormal_handling_OK()) {
|
||||||
|
// We just dlopen()ed a library that mangled the floating-point
|
||||||
|
// flags. Silently fix things now.
|
||||||
|
int rtn = fesetenv(&default_fenv);
|
||||||
|
assert(rtn == 0, "fesetenv must succeed");
|
||||||
|
assert(IEEE_subnormal_handling_OK(), "fsetenv didn't work");
|
||||||
|
}
|
||||||
|
#endif // IA32
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
||||||
#ifdef STATIC_BUILD
|
#ifdef STATIC_BUILD
|
||||||
@ -984,7 +1020,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
|||||||
|
|
||||||
void* result;
|
void* result;
|
||||||
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
|
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
|
||||||
result = ::dlopen(filename, RTLD_LAZY);
|
result = os::Bsd::dlopen_helper(filename, RTLD_LAZY);
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
|
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
|
||||||
// Successful loading
|
// Successful loading
|
||||||
@ -1017,7 +1053,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
|||||||
|
|
||||||
void* result;
|
void* result;
|
||||||
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
|
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
|
||||||
result = ::dlopen(filename, RTLD_LAZY);
|
result = os::Bsd::dlopen_helper(filename, RTLD_LAZY);
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
|
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
|
||||||
// Successful loading
|
// Successful loading
|
||||||
|
@ -70,6 +70,8 @@ class os::Bsd {
|
|||||||
// Real-time clock functions
|
// Real-time clock functions
|
||||||
static void clock_init(void);
|
static void clock_init(void);
|
||||||
|
|
||||||
|
static void *dlopen_helper(const char *path, int mode);
|
||||||
|
|
||||||
// Stack repair handling
|
// Stack repair handling
|
||||||
|
|
||||||
// none present
|
// none present
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
# include <signal.h>
|
# include <signal.h>
|
||||||
# include <endian.h>
|
# include <endian.h>
|
||||||
# include <errno.h>
|
# include <errno.h>
|
||||||
|
# include <fenv.h>
|
||||||
# include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
@ -1802,6 +1803,25 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
|
void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
|
||||||
|
#ifndef IA32
|
||||||
|
// Save and restore the floating-point environment around dlopen().
|
||||||
|
// There are known cases where global library initialization sets
|
||||||
|
// FPU flags that affect computation accuracy, for example, enabling
|
||||||
|
// Flush-To-Zero and Denormals-Are-Zero. Do not let those libraries
|
||||||
|
// break Java arithmetic. Unfortunately, this might affect libraries
|
||||||
|
// that might depend on these FPU features for performance and/or
|
||||||
|
// numerical "accuracy", but we need to protect Java semantics first
|
||||||
|
// and foremost. See JDK-8295159.
|
||||||
|
|
||||||
|
// This workaround is ineffective on IA32 systems because the MXCSR
|
||||||
|
// register (which controls flush-to-zero mode) is not stored in the
|
||||||
|
// legacy fenv.
|
||||||
|
|
||||||
|
fenv_t default_fenv;
|
||||||
|
int rtn = fegetenv(&default_fenv);
|
||||||
|
assert(rtn == 0, "fegetenv must succeed");
|
||||||
|
#endif // IA32
|
||||||
|
|
||||||
void* result;
|
void* result;
|
||||||
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
|
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
|
||||||
result = ::dlopen(filename, RTLD_LAZY);
|
result = ::dlopen(filename, RTLD_LAZY);
|
||||||
@ -1820,6 +1840,16 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) {
|
|||||||
} else {
|
} else {
|
||||||
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
|
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
|
||||||
log_info(os)("shared library load of %s was successful", filename);
|
log_info(os)("shared library load of %s was successful", filename);
|
||||||
|
#ifndef IA32
|
||||||
|
// Quickly test to make sure subnormals are correctly handled.
|
||||||
|
if (! IEEE_subnormal_handling_OK()) {
|
||||||
|
// We just dlopen()ed a library that mangled the floating-point
|
||||||
|
// flags. Silently fix things now.
|
||||||
|
int rtn = fesetenv(&default_fenv);
|
||||||
|
assert(rtn == 0, "fesetenv must succeed");
|
||||||
|
assert(IEEE_subnormal_handling_OK(), "fsetenv didn't work");
|
||||||
|
}
|
||||||
|
#endif // IA32
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -409,3 +409,32 @@ STATIC_ASSERT(nth_bit(1|2) == 0x8);
|
|||||||
|
|
||||||
STATIC_ASSERT(right_n_bits(3) == 0x7);
|
STATIC_ASSERT(right_n_bits(3) == 0x7);
|
||||||
STATIC_ASSERT(right_n_bits(1|2) == 0x7);
|
STATIC_ASSERT(right_n_bits(1|2) == 0x7);
|
||||||
|
|
||||||
|
// Check for Flush-To-Zero mode
|
||||||
|
|
||||||
|
// On some processors faster execution can be achieved by setting a
|
||||||
|
// mode to return zero for extremely small results, rather than an
|
||||||
|
// IEEE-754 subnormal number. This mode is not compatible with the
|
||||||
|
// Java Language Standard.
|
||||||
|
|
||||||
|
// We need the addition of _large_subnormal and _small_subnormal to be
|
||||||
|
// performed at runtime. _small_subnormal is volatile so that
|
||||||
|
// expressions involving it cannot be evaluated at compile time.
|
||||||
|
static const double large_subnormal_double
|
||||||
|
= jdouble_cast(0x0030000000000000); // 0x1.0p-1020;
|
||||||
|
static const volatile double small_subnormal_double
|
||||||
|
= jdouble_cast(0x0000000000000003); // 0x0.0000000000003p-1022;
|
||||||
|
|
||||||
|
// Quickly test to make sure IEEE-754 subnormal numbers are correctly
|
||||||
|
// handled.
|
||||||
|
bool IEEE_subnormal_handling_OK() {
|
||||||
|
// _small_subnormal is the smallest subnormal number that has two
|
||||||
|
// bits set. _large_subnormal is a number such that, when
|
||||||
|
// _small_subnormal is added to it, must be rounded according to the
|
||||||
|
// mode. These two tests detect the rounding mode in use. If
|
||||||
|
// subnormals are turned off (i.e. subnormals-are-zero) flush-to-
|
||||||
|
// zero mode is in use.
|
||||||
|
|
||||||
|
return (large_subnormal_double + small_subnormal_double > large_subnormal_double
|
||||||
|
&& -large_subnormal_double - small_subnormal_double < -large_subnormal_double);
|
||||||
|
}
|
||||||
|
@ -1335,4 +1335,8 @@ template<typename K> int primitive_compare(const K& k0, const K& k1) {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
std::add_rvalue_reference_t<T> declval() noexcept;
|
std::add_rvalue_reference_t<T> declval() noexcept;
|
||||||
|
|
||||||
|
// Quickly test to make sure IEEE-754 subnormal numbers are correctly
|
||||||
|
// handled.
|
||||||
|
bool IEEE_subnormal_handling_OK();
|
||||||
|
|
||||||
#endif // SHARE_UTILITIES_GLOBALDEFINITIONS_HPP
|
#endif // SHARE_UTILITIES_GLOBALDEFINITIONS_HPP
|
||||||
|
@ -75,6 +75,9 @@ compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all
|
|||||||
|
|
||||||
compiler/codecache/CheckLargePages.java 8317831 linux-x64
|
compiler/codecache/CheckLargePages.java 8317831 linux-x64
|
||||||
|
|
||||||
|
compiler/floatingpoint/TestSubnormalFloat.java 8317810 generic-i586
|
||||||
|
compiler/floatingpoint/TestSubnormalDouble.java 8317810 generic-i586
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
# :hotspot_gc
|
# :hotspot_gc
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8295159
|
||||||
|
* @summary DSO created with -ffast-math breaks Java floating-point arithmetic
|
||||||
|
* @run main/othervm/native compiler.floatingpoint.TestSubnormalDouble
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compiler.floatingpoint;
|
||||||
|
|
||||||
|
import static java.lang.System.loadLibrary;
|
||||||
|
|
||||||
|
public class TestSubnormalDouble {
|
||||||
|
static volatile double lastDouble;
|
||||||
|
|
||||||
|
private static void testDoubles() {
|
||||||
|
lastDouble = 0x1.0p-1074;
|
||||||
|
for (double x = lastDouble * 2; x <= 0x1.0p1022; x *= 2) {
|
||||||
|
if (x != x || x <= lastDouble) {
|
||||||
|
throw new RuntimeException("TEST FAILED: " + x);
|
||||||
|
}
|
||||||
|
lastDouble = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
testDoubles();
|
||||||
|
System.out.println("Loading libfast-math.so");
|
||||||
|
loadLibrary("fast-math");
|
||||||
|
testDoubles();
|
||||||
|
System.out.println("Test passed.");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8295159
|
||||||
|
* @summary DSO created with -ffast-math breaks Java floating-point arithmetic
|
||||||
|
* @run main/othervm/native compiler.floatingpoint.TestSubnormalFloat
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compiler.floatingpoint;
|
||||||
|
|
||||||
|
import static java.lang.System.loadLibrary;
|
||||||
|
|
||||||
|
public class TestSubnormalFloat {
|
||||||
|
static volatile float lastFloat;
|
||||||
|
|
||||||
|
private static void testFloats() {
|
||||||
|
lastFloat = 0x1.0p-149f;
|
||||||
|
for (float x = lastFloat * 2; x <= 0x1.0p127f; x *= 2) {
|
||||||
|
if (x != x || x <= lastFloat) {
|
||||||
|
throw new RuntimeException("TEST FAILED: " + x);
|
||||||
|
}
|
||||||
|
lastFloat = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
testFloats();
|
||||||
|
System.out.println("Loading libfast-math.so");
|
||||||
|
loadLibrary("fast-math");
|
||||||
|
testFloats();
|
||||||
|
System.out.println("Test passed.");
|
||||||
|
}
|
||||||
|
}
|
60
test/hotspot/jtreg/compiler/floatingpoint/libfast-math.c
Normal file
60
test/hotspot/jtreg/compiler/floatingpoint/libfast-math.c
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Red Hat, Inc. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "jni.h"
|
||||||
|
|
||||||
|
// See GCC bug 55522:
|
||||||
|
//
|
||||||
|
// "When used at link-time, [ GCC with -ffast-math ] may include
|
||||||
|
// libraries or startup files that change the default FPU control word
|
||||||
|
// or other similar optimizations."
|
||||||
|
//
|
||||||
|
// This breaks Java's floating point arithmetic.
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
|
||||||
|
// On systems on which GCC bug 55522 has been fixed, this constructor
|
||||||
|
// serves to reproduce that bug for the purposes of testing HotSpot.
|
||||||
|
static void __attribute__((constructor)) set_flush_to_zero(void) {
|
||||||
|
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
|
||||||
|
#define MXCSR_DAZ (1 << 6) /* Enable denormals are zero mode */
|
||||||
|
#define MXCSR_FTZ (1 << 15) /* Enable flush to zero mode */
|
||||||
|
unsigned int mxcsr = __builtin_ia32_stmxcsr ();
|
||||||
|
mxcsr |= MXCSR_DAZ | MXCSR_FTZ;
|
||||||
|
__builtin_ia32_ldmxcsr (mxcsr);
|
||||||
|
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
|
||||||
|
#define _FPU_FPCR_FZ (unsigned long)0x1000000
|
||||||
|
#define _FPU_SETCW(fpcr) \
|
||||||
|
__asm__ __volatile__ ("msr fpcr, %0" : : "r" (fpcr));
|
||||||
|
|
||||||
|
/* Flush to zero, round to nearest, IEEE exceptions disabled. */
|
||||||
|
_FPU_SETCW (_FPU_FPCR_FZ);
|
||||||
|
|
||||||
|
#endif // CPU arch
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // defined(__GNUC__)
|
Loading…
Reference in New Issue
Block a user