8224162: assert(profile.count() == 0) failed: sanity in InlineTree::is_not_reached
authorjiefu
Thu, 06 Jun 2019 13:45:59 +0300
changeset 55252 6502d6a92fe2
parent 55251 92eec0732eed
child 55253 3c905e67e380
8224162: assert(profile.count() == 0) failed: sanity in InlineTree::is_not_reached Reviewed-by: vlivanov, kvn
src/hotspot/share/ci/ciMethod.cpp
src/hotspot/share/ci/ciMethod.hpp
src/hotspot/share/oops/methodData.hpp
src/hotspot/share/utilities/globalDefinitions.hpp
test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java
--- a/src/hotspot/share/ci/ciMethod.cpp	Tue Jun 04 17:56:16 2019 +0800
+++ b/src/hotspot/share/ci/ciMethod.cpp	Thu Jun 06 13:45:59 2019 +0300
@@ -462,6 +462,27 @@
 
 
 // ------------------------------------------------------------------
+// ciMethod::check_overflow
+//
+// Check whether the profile counter is overflowed and adjust if true.
+// For invoke* it will turn negative values into max_jint,
+// and for checkcast/aastore/instanceof turn positive values into min_jint.
+int ciMethod::check_overflow(int c, Bytecodes::Code code) {
+  switch (code) {
+    case Bytecodes::_aastore:    // fall-through
+    case Bytecodes::_checkcast:  // fall-through
+    case Bytecodes::_instanceof: {
+      return (c > 0 ? min_jint : c); // always non-positive
+    }
+    default: {
+      assert(Bytecodes::is_invoke(code), "%s", Bytecodes::name(code));
+      return (c < 0 ? max_jint : c); // always non-negative
+    }
+  }
+}
+
+
+// ------------------------------------------------------------------
 // ciMethod::call_profile_at_bci
 //
 // Get the ciCallProfile for the invocation of this method.
@@ -473,7 +494,7 @@
     ciProfileData* data = method_data()->bci_to_data(bci);
     if (data != NULL && data->is_CounterData()) {
       // Every profiled call site has a counter.
-      int count = data->as_CounterData()->count();
+      int count = check_overflow(data->as_CounterData()->count(), java_code_at_bci(bci));
 
       if (!data->is_ReceiverTypeData()) {
         result._receiver_count[0] = 0;  // that's a definite zero
@@ -502,9 +523,9 @@
         for (uint i = 0; i < call->row_limit(); i++) {
           ciKlass* receiver = call->receiver(i);
           if (receiver == NULL)  continue;
-          int rcount = call->receiver_count(i) + epsilon;
+          int rcount = saturated_add(call->receiver_count(i), epsilon);
           if (rcount == 0) rcount = 1; // Should be valid value
-          receivers_count_total += rcount;
+          receivers_count_total = saturated_add(receivers_count_total, rcount);
           // Add the receiver to result data.
           result.add_receiver(receiver, rcount);
           // If we extend profiling to record methods,
@@ -534,7 +555,7 @@
         // do nothing.  Otherwise, increase count to be the sum of all
         // receiver's counts.
         if (count >= 0) {
-          count += receivers_count_total;
+          count = saturated_add(count, receivers_count_total);
         }
       }
       result._count = count;
--- a/src/hotspot/share/ci/ciMethod.hpp	Tue Jun 04 17:56:16 2019 +0800
+++ b/src/hotspot/share/ci/ciMethod.hpp	Thu Jun 06 13:45:59 2019 +0300
@@ -126,6 +126,9 @@
   void assert_virtual_call_type_ok(int bci);
   void assert_call_type_ok(int bci);
 
+  // Check and update the profile counter in case of overflow
+  static int check_overflow(int c, Bytecodes::Code code);
+
  public:
   void check_is_loaded() const                   { assert(is_loaded(), "not loaded"); }
 
--- a/src/hotspot/share/oops/methodData.hpp	Tue Jun 04 17:56:16 2019 +0800
+++ b/src/hotspot/share/oops/methodData.hpp	Thu Jun 06 13:45:59 2019 +0300
@@ -558,8 +558,14 @@
   }
 
   // Direct accessor
-  uint count() const {
-    return uint_at(count_off);
+  int count() const {
+    intptr_t raw_data = intptr_at(count_off);
+    if (raw_data > max_jint) {
+      raw_data = max_jint;
+    } else if (raw_data < min_jint) {
+      raw_data = min_jint;
+    }
+    return int(raw_data);
   }
 
   // Code generation support
@@ -570,8 +576,8 @@
     return cell_offset(counter_cell_count);
   }
 
-  void set_count(uint count) {
-    set_uint_at(count_off, count);
+  void set_count(int count) {
+    set_int_at(count_off, count);
   }
 
   void print_data_on(outputStream* st, const char* extra = NULL) const;
--- a/src/hotspot/share/utilities/globalDefinitions.hpp	Tue Jun 04 17:56:16 2019 +0800
+++ b/src/hotspot/share/utilities/globalDefinitions.hpp	Thu Jun 06 13:45:59 2019 +0300
@@ -1085,6 +1085,28 @@
 
 #undef JAVA_INTEGER_OP
 
+//----------------------------------------------------------------------------------------------------
+// The goal of this code is to provide saturating operations for int/uint.
+// Checks overflow conditions and saturates the result to min_jint/max_jint.
+#define SATURATED_INTEGER_OP(OP, NAME, TYPE1, TYPE2) \
+inline int NAME (TYPE1 in1, TYPE2 in2) {             \
+  jlong res = static_cast<jlong>(in1);               \
+  res OP ## = static_cast<jlong>(in2);               \
+  if (res > max_jint) {                              \
+    res = max_jint;                                  \
+  } else if (res < min_jint) {                       \
+    res = min_jint;                                  \
+  }                                                  \
+  return static_cast<int>(res);                      \
+}
+
+SATURATED_INTEGER_OP(+, saturated_add, int, int)
+SATURATED_INTEGER_OP(+, saturated_add, int, uint)
+SATURATED_INTEGER_OP(+, saturated_add, uint, int)
+SATURATED_INTEGER_OP(+, saturated_add, uint, uint)
+
+#undef SATURATED_INTEGER_OP
+
 // Dereference vptr
 // All C++ compilers that we know of have the vtbl pointer in the first
 // word.  If there are exceptions, this function needs to be made compiler
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/profiling/TestProfileCounterOverflow.java	Thu Jun 06 13:45:59 2019 +0300
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019, Loongson Technology Co. Ltd. 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 8224162
+ * @summary Profile counter for a call site may overflow.
+ * @run main/othervm -Xbatch -XX:-UseOnStackReplacement -XX:MaxTrivialSize=0 compiler.profiling.TestProfileCounterOverflow
+ */
+
+package compiler.profiling;
+
+public class TestProfileCounterOverflow {
+    public static void test(long iterations) {
+        for (long j = 0; j < iterations; j++) {
+            call();
+        }
+    }
+
+    public static void call() {}
+
+    public static void main(String[] args) {
+        // trigger profiling on tier3
+        for (int i = 0; i < 500; i++) {
+            test(1);
+        }
+
+        test(Integer.MAX_VALUE + 10000L); // overflow call counter
+
+        // trigger c2 compilation
+        for (int i = 0; i < 10_000; i++) {
+            test(1);
+        }
+        System.out.println("TEST PASSED");
+    }
+}