JDK-6695288 : runThese tests expr30303 and drem00301m1 fail when compiled code executes without deopt
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: x86
  • Submitted: 2008-04-29
  • Updated: 2011-03-08
  • Resolved: 2011-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 Other
6u14Fixed 7Fixed hs13Fixed
Related Reports
Relates :  
Description
Two tests in runThese can fail due to wrong constant folding of the drem bytecode:

[Enter:javasoft.sqe.tests.lang.expr303.expr30303.expr30303]
expr30303: failure #12
#Failed; javasoft.sqe.tests.lang.expr303.expr30303.expr30303; (1,0,0,1,0)
[Exit:javasoft.sqe.tests.lang.expr303.expr30303.expr30303]

[Enter:javasoft.sqe.tests.vm.instr.drem.drem003.drem00301m1.drem00301m1]
#Failed; javasoft.sqe.tests.vm.instr.drem.drem003.drem00301m1.drem00301m1; (1,0,0,1,0)
[Exit:javasoft.sqe.tests.vm.instr.drem.drem003.drem00301m1.drem00301m1]


The bug only affects the expression x%x, where x is Double.POSITIVE_INFINITY.

This only occurs when an actual ModDNode is created, because the bug is in ModDNode::Value.

The affected platform is x86/32, because there is a match rule for ModD in that AD file.

This problem has always been in C2, but it did not manifest because the two tests have many different subtests, and until now the code generated by -Xcomp has deoptimized before executing any compiled code for the failing subtest.

The problem has been in the code for years, but only shows up now in pre-integration testing to the well-known classes optimization (6652736), which slightly reduces deoptimization behavior.

Comments
EVALUATION See Description.
21-05-2008

SUGGESTED FIX diff --git a/src/share/vm/opto/divnode.cpp b/src/share/vm/opto/divnode.cpp --- a/src/share/vm/opto/divnode.cpp +++ b/src/share/vm/opto/divnode.cpp @@ -872,56 +872,32 @@ const Type *ModFNode::Value( PhaseTransf (t1 == Type::BOTTOM) || (t2 == Type::BOTTOM) ) return bot; + // If both numbers are not constants, we know nothing. + if ((t1->base() != Type::FloatCon) || (t2->base() != Type::FloatCon)) { + return Type::FLOAT; // note: x%x can be either NaN or 0 + } + + float f1 = t1->getf(); + float f2 = t2->getf(); + jint x1 = jint_cast(f1); + jint x2 = jint_cast(f2); + // If either is a NaN, return an input NaN - if( g_isnan(t1->getf()) ) return t1; - if( g_isnan(t2->getf()) ) return t2; + if (g_isnan(f1)) return t1; + if (g_isnan(f2)) return t2; - // It is not worth trying to constant fold this stuff! - return Type::FLOAT; - - /* - // If dividend is infinity or divisor is zero, or both, the result is NaN - if( !g_isfinite(t1->getf()) || ((t2->getf() == 0.0) || (jint_cast(t2->getf()) == 0x80000000)) ) - - // X MOD infinity = X - if( !g_isfinite(t2->getf()) && !g_isnan(t2->getf()) ) return t1; - // 0 MOD finite = dividend (positive or negative zero) - // Not valid for: NaN MOD any; any MOD nan; 0 MOD 0; or for 0 MOD NaN - // NaNs are handled previously. - if( !(t2->getf() == 0.0) && !((int)t2->getf() == 0x80000000)) { - if (((t1->getf() == 0.0) || ((int)t1->getf() == 0x80000000)) && g_isfinite(t2->getf()) ) { - return t1; - } - } - // X MOD X is 0 - // Does not work for variables because of NaN's - if( phase->eqv( in(1), in(2) ) && t1->base() == Type::FloatCon) - if (!g_isnan(t1->getf()) && (t1->getf() != 0.0) && ((int)t1->getf() != 0x80000000)) { - if(t1->getf() < 0.0) { - float result = jfloat_cast(0x80000000); - return TypeF::make( result ); - } - else - return TypeF::ZERO; - } - - // If both numbers are not constants, we know nothing. - if( (t1->base() != Type::FloatCon) || (t2->base() != Type::FloatCon) ) + // If operand is infinity or divisor is +/- zero, punt. + if (!g_isfinite(f1) || !g_isfinite(f2) || (x2 << 1) == 0) return Type::FLOAT; // We must be modulo'ing 2 float constants. // Make sure that the sign of the fmod is equal to the sign of the dividend - float result = (float)fmod( t1->getf(), t2->getf() ); - float dividend = t1->getf(); - if( (dividend < 0.0) || ((int)dividend == 0x80000000) ) { - if( result > 0.0 ) - result = 0.0 - result; - else if( result == 0.0 ) { - result = jfloat_cast(0x80000000); - } + jint xr = jint_cast(fmod(f1, f2)); + if ((x1 ^ xr) < 0) { + xr ^= min_jint; } - return TypeF::make( result ); - */ + + return TypeF::make(jfloat_cast(xr)); } @@ -940,33 +916,32 @@ const Type *ModDNode::Value( PhaseTransf (t1 == Type::BOTTOM) || (t2 == Type::BOTTOM) ) return bot; - // If either is a NaN, return an input NaN - if( g_isnan(t1->getd()) ) return t1; - if( g_isnan(t2->getd()) ) return t2; - // X MOD infinity = X - if( !g_isfinite(t2->getd())) return t1; - // 0 MOD finite = dividend (positive or negative zero) - // Not valid for: NaN MOD any; any MOD nan; 0 MOD 0; or for 0 MOD NaN - // NaNs are handled previously. - if( !(t2->getd() == 0.0) ) { - if( t1->getd() == 0.0 && g_isfinite(t2->getd()) ) { - return t1; - } + // If both numbers are not constants, we know nothing. + if ((t1->base() != Type::DoubleCon) || (t2->base() != Type::DoubleCon)) { + return Type::DOUBLE; // note: x%x can be either NaN or 0 } - // X MOD X is 0 - // does not work for variables because of NaN's - if( phase->eqv( in(1), in(2) ) && t1->base() == Type::DoubleCon ) - if (!g_isnan(t1->getd()) && t1->getd() != 0.0) - return TypeD::ZERO; + double f1 = t1->getd(); + double f2 = t2->getd(); + jlong x1 = jlong_cast(f1); + jlong x2 = jlong_cast(f2); + // If either is a NaN, return an input NaN + if (g_isnan(f1)) return t1; + if (g_isnan(f2)) return t2; - // If both numbers are not constants, we know nothing. - if( (t1->base() != Type::DoubleCon) || (t2->base() != Type::DoubleCon) ) + // If operand is infinity or divisor is +/- zero, punt. + if (!g_isfinite(f1) || !g_isfinite(f2) || (x2 << 1) == 0) return Type::DOUBLE; // We must be modulo'ing 2 double constants. - return TypeD::make( fmod( t1->getd(), t2->getd() ) ); + // Make sure that the sign of the fmod is equal to the sign of the dividend + jlong xr = jlong_cast(fmod(f1, f2)); + if ((x1 ^ xr) < 0) { + xr ^= min_jlong; + } + + return TypeF::make(jfloat_cast(xr)); } //=============================================================================
29-04-2008