Mercurial > hg > truffle
annotate src/share/vm/opto/loopUnswitch.cpp @ 452:00b023ae2d78
6722113: CMS: Incorrect overflow handling during precleaning of Reference lists
Summary: When we encounter marking stack overflow during precleaning of Reference lists, we were using the overflow list mechanism, which can cause problems on account of mutating the mark word of the header because of conflicts with mutator accesses and updates of that field. Instead we should use the usual mechanism for overflow handling in concurrent phases, namely dirtying of the card on which the overflowed object lies. Since precleaning effectively does a form of discovered list processing, albeit with discovery enabled, we needed to adjust some code to be correct in the face of interleaved processing and discovery.
Reviewed-by: apetrusenko, jcoomes
author | ysr |
---|---|
date | Thu, 20 Nov 2008 12:27:41 -0800 |
parents | 9c2ecc2ffb12 |
children | 98cb887364d3 |
rev | line source |
---|---|
0 | 1 /* |
196 | 2 * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 #include "incls/_precompiled.incl" | |
26 #include "incls/_loopUnswitch.cpp.incl" | |
27 | |
28 //================= Loop Unswitching ===================== | |
29 // | |
30 // orig: transformed: | |
31 // if (invariant-test) then | |
32 // loop loop | |
33 // stmt1 stmt1 | |
34 // if (invariant-test) then stmt2 | |
35 // stmt2 stmt4 | |
36 // else endloop | |
37 // stmt3 else | |
38 // endif loop [clone] | |
39 // stmt4 stmt1 [clone] | |
40 // endloop stmt3 | |
41 // stmt4 [clone] | |
42 // endloop | |
43 // endif | |
44 // | |
45 // Note: the "else" clause may be empty | |
46 | |
47 //------------------------------policy_unswitching----------------------------- | |
48 // Return TRUE or FALSE if the loop should be unswitched | |
49 // (ie. clone loop with an invariant test that does not exit the loop) | |
50 bool IdealLoopTree::policy_unswitching( PhaseIdealLoop *phase ) const { | |
51 if( !LoopUnswitching ) { | |
52 return false; | |
53 } | |
108 | 54 if (!_head->is_Loop()) { |
55 return false; | |
56 } | |
0 | 57 uint nodes_left = MaxNodeLimit - phase->C->unique(); |
58 if (2 * _body.size() > nodes_left) { | |
59 return false; // Too speculative if running low on nodes. | |
60 } | |
61 LoopNode* head = _head->as_Loop(); | |
62 if (head->unswitch_count() + 1 > head->unswitch_max()) { | |
63 return false; | |
64 } | |
65 return phase->find_unswitching_candidate(this) != NULL; | |
66 } | |
67 | |
68 //------------------------------find_unswitching_candidate----------------------------- | |
69 // Find candidate "if" for unswitching | |
70 IfNode* PhaseIdealLoop::find_unswitching_candidate(const IdealLoopTree *loop) const { | |
71 | |
72 // Find first invariant test that doesn't exit the loop | |
73 LoopNode *head = loop->_head->as_Loop(); | |
74 IfNode* unswitch_iff = NULL; | |
75 Node* n = head->in(LoopNode::LoopBackControl); | |
76 while (n != head) { | |
77 Node* n_dom = idom(n); | |
78 if (n->is_Region()) { | |
79 if (n_dom->is_If()) { | |
80 IfNode* iff = n_dom->as_If(); | |
81 if (iff->in(1)->is_Bool()) { | |
82 BoolNode* bol = iff->in(1)->as_Bool(); | |
83 if (bol->in(1)->is_Cmp()) { | |
84 // If condition is invariant and not a loop exit, | |
85 // then found reason to unswitch. | |
86 if (loop->is_invariant(bol) && !loop->is_loop_exit(iff)) { | |
87 unswitch_iff = iff; | |
88 } | |
89 } | |
90 } | |
91 } | |
92 } | |
93 n = n_dom; | |
94 } | |
95 return unswitch_iff; | |
96 } | |
97 | |
98 //------------------------------do_unswitching----------------------------- | |
99 // Clone loop with an invariant test (that does not exit) and | |
100 // insert a clone of the test that selects which version to | |
101 // execute. | |
102 void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) { | |
103 | |
104 // Find first invariant test that doesn't exit the loop | |
105 LoopNode *head = loop->_head->as_Loop(); | |
106 | |
107 IfNode* unswitch_iff = find_unswitching_candidate((const IdealLoopTree *)loop); | |
108 assert(unswitch_iff != NULL, "should be at least one"); | |
109 | |
110 // Need to revert back to normal loop | |
111 if (head->is_CountedLoop() && !head->as_CountedLoop()->is_normal_loop()) { | |
112 head->as_CountedLoop()->set_normal_loop(); | |
113 } | |
114 | |
115 ProjNode* proj_true = create_slow_version_of_loop(loop, old_new); | |
116 | |
117 assert(proj_true->is_IfTrue() && proj_true->unique_ctrl_out() == head, "by construction"); | |
118 | |
119 // Increment unswitch count | |
120 LoopNode* head_clone = old_new[head->_idx]->as_Loop(); | |
121 int nct = head->unswitch_count() + 1; | |
122 head->set_unswitch_count(nct); | |
123 head_clone->set_unswitch_count(nct); | |
124 | |
125 // Add test to new "if" outside of loop | |
126 IfNode* invar_iff = proj_true->in(0)->as_If(); | |
127 Node* invar_iff_c = invar_iff->in(0); | |
128 BoolNode* bol = unswitch_iff->in(1)->as_Bool(); | |
129 invar_iff->set_req(1, bol); | |
130 invar_iff->_prob = unswitch_iff->_prob; | |
131 | |
132 ProjNode* proj_false = invar_iff->proj_out(0)->as_Proj(); | |
133 | |
134 // Hoist invariant casts out of each loop to the appropiate | |
135 // control projection. | |
136 | |
137 Node_List worklist; | |
138 | |
139 for (DUIterator_Fast imax, i = unswitch_iff->fast_outs(imax); i < imax; i++) { | |
140 ProjNode* proj= unswitch_iff->fast_out(i)->as_Proj(); | |
141 // Copy to a worklist for easier manipulation | |
142 for (DUIterator_Fast jmax, j = proj->fast_outs(jmax); j < jmax; j++) { | |
143 Node* use = proj->fast_out(j); | |
144 if (use->Opcode() == Op_CheckCastPP && loop->is_invariant(use->in(1))) { | |
145 worklist.push(use); | |
146 } | |
147 } | |
148 ProjNode* invar_proj = invar_iff->proj_out(proj->_con)->as_Proj(); | |
149 while (worklist.size() > 0) { | |
150 Node* use = worklist.pop(); | |
151 Node* nuse = use->clone(); | |
152 nuse->set_req(0, invar_proj); | |
153 _igvn.hash_delete(use); | |
154 use->set_req(1, nuse); | |
155 _igvn._worklist.push(use); | |
156 register_new_node(nuse, invar_proj); | |
157 // Same for the clone | |
158 Node* use_clone = old_new[use->_idx]; | |
159 _igvn.hash_delete(use_clone); | |
160 use_clone->set_req(1, nuse); | |
161 _igvn._worklist.push(use_clone); | |
162 } | |
163 } | |
164 | |
165 // Hardwire the control paths in the loops into if(true) and if(false) | |
166 _igvn.hash_delete(unswitch_iff); | |
167 short_circuit_if(unswitch_iff, proj_true); | |
168 _igvn._worklist.push(unswitch_iff); | |
169 | |
170 IfNode* unswitch_iff_clone = old_new[unswitch_iff->_idx]->as_If(); | |
171 _igvn.hash_delete(unswitch_iff_clone); | |
172 short_circuit_if(unswitch_iff_clone, proj_false); | |
173 _igvn._worklist.push(unswitch_iff_clone); | |
174 | |
175 // Reoptimize loops | |
176 loop->record_for_igvn(); | |
177 for(int i = loop->_body.size() - 1; i >= 0 ; i--) { | |
178 Node *n = loop->_body[i]; | |
179 Node *n_clone = old_new[n->_idx]; | |
180 _igvn._worklist.push(n_clone); | |
181 } | |
182 | |
183 #ifndef PRODUCT | |
184 if (TraceLoopUnswitching) { | |
185 tty->print_cr("Loop unswitching orig: %d @ %d new: %d @ %d", | |
186 head->_idx, unswitch_iff->_idx, | |
187 old_new[head->_idx]->_idx, unswitch_iff_clone->_idx); | |
188 } | |
189 #endif | |
190 | |
191 C->set_major_progress(); | |
192 } | |
193 | |
194 //-------------------------create_slow_version_of_loop------------------------ | |
195 // Create a slow version of the loop by cloning the loop | |
196 // and inserting an if to select fast-slow versions. | |
197 // Return control projection of the entry to the fast version. | |
198 ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop, | |
199 Node_List &old_new) { | |
200 LoopNode* head = loop->_head->as_Loop(); | |
201 Node* entry = head->in(LoopNode::EntryControl); | |
202 _igvn.hash_delete(entry); | |
203 _igvn._worklist.push(entry); | |
204 IdealLoopTree* outer_loop = loop->_parent; | |
205 | |
206 Node *cont = _igvn.intcon(1); | |
207 set_ctrl(cont, C->root()); | |
216
8d191a7697e2
6715633: when matching a memory node the adr_type should not change
kvn
parents:
108
diff
changeset
|
208 Node* opq = new (C, 2) Opaque1Node(C, cont); |
0 | 209 register_node(opq, outer_loop, entry, dom_depth(entry)); |
210 Node *bol = new (C, 2) Conv2BNode(opq); | |
211 register_node(bol, outer_loop, entry, dom_depth(entry)); | |
212 IfNode* iff = new (C, 2) IfNode(entry, bol, PROB_MAX, COUNT_UNKNOWN); | |
213 register_node(iff, outer_loop, entry, dom_depth(entry)); | |
214 ProjNode* iffast = new (C, 1) IfTrueNode(iff); | |
215 register_node(iffast, outer_loop, iff, dom_depth(iff)); | |
216 ProjNode* ifslow = new (C, 1) IfFalseNode(iff); | |
217 register_node(ifslow, outer_loop, iff, dom_depth(iff)); | |
218 | |
219 // Clone the loop body. The clone becomes the fast loop. The | |
220 // original pre-header will (illegally) have 2 control users (old & new loops). | |
221 clone_loop(loop, old_new, dom_depth(head), iff); | |
222 assert(old_new[head->_idx]->is_Loop(), "" ); | |
223 | |
224 // Fast (true) control | |
225 _igvn.hash_delete(head); | |
226 head->set_req(LoopNode::EntryControl, iffast); | |
227 set_idom(head, iffast, dom_depth(head)); | |
228 _igvn._worklist.push(head); | |
229 | |
230 // Slow (false) control | |
231 LoopNode* slow_head = old_new[head->_idx]->as_Loop(); | |
232 _igvn.hash_delete(slow_head); | |
233 slow_head->set_req(LoopNode::EntryControl, ifslow); | |
234 set_idom(slow_head, ifslow, dom_depth(slow_head)); | |
235 _igvn._worklist.push(slow_head); | |
236 | |
237 recompute_dom_depth(); | |
238 | |
239 return iffast; | |
240 } |