United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6695288 : runThese tests expr30303 and drem00301m1 fail when compiled code executes without deopt

Details
Type:
Bug
Submit Date:
2008-04-29
Status:
Closed
Updated Date:
2011-03-08
Project Name:
JDK
Resolved Date:
2011-03-08
Component:
hotspot
OS:
generic
Sub-Component:
compiler
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
7
Fixed Versions:
hs13 (b01)

Related Reports
Backport:
Backport:
Relates:

Sub Tasks

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
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));
 }
 
 //=============================================================================
                                     
2008-04-29
EVALUATION

See Description.
                                     
2008-05-21



Hardware and Software, Engineered to Work Together