6869327: Add new C2 flag to keep safepoints in counted loops.
Reviewed-by: kvn, shade
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Thu Dec 03 22:30:17 2015 -0800
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp Fri Dec 04 14:06:38 2015 +0100
@@ -213,6 +213,9 @@
notproduct(bool, TraceProfileTripCount, false, \
"Trace profile loop trip count information") \
\
+ product(bool, UseCountedLoopSafepoints, false, \
+ "Force counted loops to keep a safepoint") \
+ \
product(bool, UseLoopPredicate, true, \
"Generate a predicate to select fast/slow loop versions") \
\
--- a/hotspot/src/share/vm/opto/loopnode.cpp Thu Dec 03 22:30:17 2015 -0800
+++ b/hotspot/src/share/vm/opto/loopnode.cpp Fri Dec 04 14:06:38 2015 +0100
@@ -690,14 +690,16 @@
} // LoopLimitCheck
- // Check for SafePoint on backedge and remove
- Node *sfpt = x->in(LoopNode::LoopBackControl);
- if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) {
- lazy_replace( sfpt, iftrue );
- if (loop->_safepts != NULL) {
- loop->_safepts->yank(sfpt);
+ if (!UseCountedLoopSafepoints) {
+ // Check for SafePoint on backedge and remove
+ Node *sfpt = x->in(LoopNode::LoopBackControl);
+ if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) {
+ lazy_replace( sfpt, iftrue );
+ if (loop->_safepts != NULL) {
+ loop->_safepts->yank(sfpt);
+ }
+ loop->_tail = iftrue;
}
- loop->_tail = iftrue;
}
// Build a canonical trip test.
@@ -786,12 +788,14 @@
lazy_replace( x, l );
set_idom(l, init_control, dom_depth(x));
- // Check for immediately preceding SafePoint and remove
- Node *sfpt2 = le->in(0);
- if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) {
- lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control));
- if (loop->_safepts != NULL) {
- loop->_safepts->yank(sfpt2);
+ if (!UseCountedLoopSafepoints) {
+ // Check for immediately preceding SafePoint and remove
+ Node *sfpt2 = le->in(0);
+ if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) {
+ lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control));
+ if (loop->_safepts != NULL) {
+ loop->_safepts->yank(sfpt2);
+ }
}
}
@@ -1813,6 +1817,33 @@
}
}
+void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) {
+ // Look for a safepoint on the idom-path.
+ Node* keep = NULL;
+ if (keep_one) {
+ // Keep one if possible
+ for (Node* i = tail(); i != _head; i = phase->idom(i)) {
+ if (i->Opcode() == Op_SafePoint && phase->get_loop(i) == this) {
+ keep = i;
+ break; // Found one
+ }
+ }
+ }
+
+ // Delete other safepoints in this loop.
+ Node_List* sfpts = _safepts;
+ if (sfpts != NULL) {
+ assert(keep == NULL || keep->Opcode() == Op_SafePoint, "not safepoint");
+ for (uint i = 0; i < sfpts->size(); i++) {
+ Node* n = sfpts->at(i);
+ assert(phase->get_loop(n) == this, "");
+ if (n != keep && phase->is_deleteable_safept(n)) {
+ phase->lazy_replace(n, n->in(TypeFunc::Control));
+ }
+ }
+ }
+}
+
//------------------------------counted_loop-----------------------------------
// Convert to counted loops where possible
void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) {
@@ -1824,42 +1855,23 @@
if (_head->is_CountedLoop() ||
phase->is_counted_loop(_head, this)) {
- _has_sfpt = 1; // Indicate we do not need a safepoint here
-
- // Look for safepoints to remove.
- Node_List* sfpts = _safepts;
- if (sfpts != NULL) {
- for (uint i = 0; i < sfpts->size(); i++) {
- Node* n = sfpts->at(i);
- assert(phase->get_loop(n) == this, "");
- if (phase->is_deleteable_safept(n)) {
- phase->lazy_replace(n, n->in(TypeFunc::Control));
- }
- }
+
+ if (!UseCountedLoopSafepoints) {
+ // Indicate we do not need a safepoint here
+ _has_sfpt = 1;
}
+ // Remove safepoints
+ bool keep_one_sfpt = !(_has_call || _has_sfpt);
+ remove_safepoints(phase, keep_one_sfpt);
+
// Look for induction variables
phase->replace_parallel_iv(this);
} else if (_parent != NULL && !_irreducible) {
- // Not a counted loop.
- // Look for a safepoint on the idom-path.
- Node* sfpt = tail();
- for (; sfpt != _head; sfpt = phase->idom(sfpt)) {
- if (sfpt->Opcode() == Op_SafePoint && phase->get_loop(sfpt) == this)
- break; // Found one
- }
- // Delete other safepoints in this loop.
- Node_List* sfpts = _safepts;
- if (sfpts != NULL && sfpt != _head && sfpt->Opcode() == Op_SafePoint) {
- for (uint i = 0; i < sfpts->size(); i++) {
- Node* n = sfpts->at(i);
- assert(phase->get_loop(n) == this, "");
- if (n != sfpt && phase->is_deleteable_safept(n)) {
- phase->lazy_replace(n, n->in(TypeFunc::Control));
- }
- }
- }
+ // Not a counted loop. Keep one safepoint.
+ bool keep_one_sfpt = true;
+ remove_safepoints(phase, keep_one_sfpt);
}
// Recursively
--- a/hotspot/src/share/vm/opto/loopnode.hpp Thu Dec 03 22:30:17 2015 -0800
+++ b/hotspot/src/share/vm/opto/loopnode.hpp Fri Dec 04 14:06:38 2015 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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
@@ -429,6 +429,9 @@
// encountered.
void allpaths_check_safepts(VectorSet &visited, Node_List &stack);
+ // Remove safepoints from loop. Optionally keeping one.
+ void remove_safepoints(PhaseIdealLoop* phase, bool keep_one);
+
// Convert to counted loops where possible
void counted_loop( PhaseIdealLoop *phase );
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java Fri Dec 04 14:06:38 2015 +0100
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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 6869327
+ * @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop
+ * @library /testlibrary
+ * @modules java.base
+ * @run main UseCountedLoopSafepoints
+ */
+
+import java.util.concurrent.atomic.AtomicLong;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.OutputAnalyzer;
+
+public class UseCountedLoopSafepoints {
+ private static final AtomicLong _num = new AtomicLong(0);
+
+ // Uses the fact that an EnableBiasedLocking vmop will be started
+ // after 500ms, while we are still in the loop. If there is a
+ // safepoint in the counted loop, then we will reach safepoint
+ // very quickly. Otherwise SafepointTimeout will be hit.
+ public static void main (String args[]) throws Exception {
+ if (args.length == 1) {
+ final int loops = Integer.parseInt(args[0]);
+ for (int i = 0; i < loops; i++) {
+ _num.addAndGet(1);
+ }
+ } else {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+IgnoreUnrecognizedVMOptions",
+ "-XX:-TieredCompilation",
+ "-XX:+UseBiasedLocking",
+ "-XX:BiasedLockingStartupDelay=500",
+ "-XX:+SafepointTimeout",
+ "-XX:SafepointTimeoutDelay=2000",
+ "-XX:+UseCountedLoopSafepoints",
+ "UseCountedLoopSafepoints",
+ "2000000000"
+ );
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldNotContain("Timeout detected");
+ output.shouldHaveExitValue(0);
+ }
+ }
+}