Mercurial > hg > truffle
annotate src/share/vm/c1/c1_Optimizer.cpp @ 6862:8a5ea0a9ccc4
7127708: G1: change task num types from int to uint in concurrent mark
Summary: Change the type of various task num fields, parameters etc to unsigned and rename them to be more consistent with the other collectors. Code changes were also reviewed by Vitaly Davidovich.
Reviewed-by: johnc
Contributed-by: Kaushik Srenevasan <kaushik@twitter.com>
author | johnc |
---|---|
date | Sat, 06 Oct 2012 01:17:44 -0700 |
parents | 7eca5de9e0b6 |
children | b9a9ed0f8eeb c3e799c37717 |
rev | line source |
---|---|
0 | 1 /* |
2166
403dc4c1d7f5
6809483: hotspot:::method_entry are not correctly generated for "method()V"
never
parents:
1972
diff
changeset
|
2 * Copyright (c) 1999, 2011, Oracle and/or its affiliates. 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
579
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
579
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
579
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "c1/c1_Canonicalizer.hpp" | |
27 #include "c1/c1_Optimizer.hpp" | |
28 #include "c1/c1_ValueMap.hpp" | |
29 #include "c1/c1_ValueSet.hpp" | |
30 #include "c1/c1_ValueStack.hpp" | |
31 #include "utilities/bitMap.inline.hpp" | |
0 | 32 |
33 define_array(ValueSetArray, ValueSet*); | |
34 define_stack(ValueSetList, ValueSetArray); | |
35 | |
36 | |
37 Optimizer::Optimizer(IR* ir) { | |
38 assert(ir->is_valid(), "IR must be valid"); | |
39 _ir = ir; | |
40 } | |
41 | |
42 class CE_Eliminator: public BlockClosure { | |
43 private: | |
44 IR* _hir; | |
45 int _cee_count; // the number of CEs successfully eliminated | |
1899 | 46 int _ifop_count; // the number of IfOps successfully simplified |
0 | 47 int _has_substitution; |
48 | |
49 public: | |
1899 | 50 CE_Eliminator(IR* hir) : _cee_count(0), _ifop_count(0), _hir(hir) { |
0 | 51 _has_substitution = false; |
52 _hir->iterate_preorder(this); | |
53 if (_has_substitution) { | |
1899 | 54 // substituted some ifops/phis, so resolve the substitution |
0 | 55 SubstitutionResolver sr(_hir); |
56 } | |
57 } | |
58 int cee_count() const { return _cee_count; } | |
1899 | 59 int ifop_count() const { return _ifop_count; } |
0 | 60 |
61 void adjust_exception_edges(BlockBegin* block, BlockBegin* sux) { | |
62 int e = sux->number_of_exception_handlers(); | |
63 for (int i = 0; i < e; i++) { | |
64 BlockBegin* xhandler = sux->exception_handler_at(i); | |
65 block->add_exception_handler(xhandler); | |
66 | |
67 assert(xhandler->is_predecessor(sux), "missing predecessor"); | |
68 if (sux->number_of_preds() == 0) { | |
69 // sux is disconnected from graph so disconnect from exception handlers | |
70 xhandler->remove_predecessor(sux); | |
71 } | |
72 if (!xhandler->is_predecessor(block)) { | |
73 xhandler->add_predecessor(block); | |
74 } | |
75 } | |
76 } | |
77 | |
1899 | 78 virtual void block_do(BlockBegin* block); |
79 | |
80 private: | |
81 Value make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval); | |
82 }; | |
0 | 83 |
1899 | 84 void CE_Eliminator::block_do(BlockBegin* block) { |
85 // 1) find conditional expression | |
86 // check if block ends with an If | |
87 If* if_ = block->end()->as_If(); | |
88 if (if_ == NULL) return; | |
0 | 89 |
1899 | 90 // check if If works on int or object types |
91 // (we cannot handle If's working on long, float or doubles yet, | |
92 // since IfOp doesn't support them - these If's show up if cmp | |
93 // operations followed by If's are eliminated) | |
94 ValueType* if_type = if_->x()->type(); | |
95 if (!if_type->is_int() && !if_type->is_object()) return; | |
0 | 96 |
1899 | 97 BlockBegin* t_block = if_->tsux(); |
98 BlockBegin* f_block = if_->fsux(); | |
99 Instruction* t_cur = t_block->next(); | |
100 Instruction* f_cur = f_block->next(); | |
0 | 101 |
1899 | 102 // one Constant may be present between BlockBegin and BlockEnd |
103 Value t_const = NULL; | |
104 Value f_const = NULL; | |
105 if (t_cur->as_Constant() != NULL && !t_cur->can_trap()) { | |
106 t_const = t_cur; | |
107 t_cur = t_cur->next(); | |
108 } | |
109 if (f_cur->as_Constant() != NULL && !f_cur->can_trap()) { | |
110 f_const = f_cur; | |
111 f_cur = f_cur->next(); | |
112 } | |
0 | 113 |
1899 | 114 // check if both branches end with a goto |
115 Goto* t_goto = t_cur->as_Goto(); | |
116 if (t_goto == NULL) return; | |
117 Goto* f_goto = f_cur->as_Goto(); | |
118 if (f_goto == NULL) return; | |
0 | 119 |
1899 | 120 // check if both gotos merge into the same block |
121 BlockBegin* sux = t_goto->default_sux(); | |
122 if (sux != f_goto->default_sux()) return; | |
0 | 123 |
1899 | 124 // check if at least one word was pushed on sux_state |
4757
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
125 // inlining depths must match |
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
126 ValueStack* if_state = if_->state(); |
1899 | 127 ValueStack* sux_state = sux->state(); |
4764
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
128 if (if_state->scope()->level() > sux_state->scope()->level()) { |
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
129 while (sux_state->scope() != if_state->scope()) { |
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
130 if_state = if_state->caller_state(); |
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
131 assert(if_state != NULL, "states do not match up"); |
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
132 } |
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
133 } else if (if_state->scope()->level() < sux_state->scope()->level()) { |
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
134 while (sux_state->scope() != if_state->scope()) { |
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
135 sux_state = sux_state->caller_state(); |
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
136 assert(sux_state != NULL, "states do not match up"); |
e5ac210043cd
7123108: C1: assert(if_state != NULL) failed: states do not match up
roland
parents:
4757
diff
changeset
|
137 } |
4757
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
138 } |
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
139 |
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
140 if (sux_state->stack_size() <= if_state->stack_size()) return; |
0 | 141 |
1899 | 142 // check if phi function is present at end of successor stack and that |
143 // only this phi was pushed on the stack | |
4757
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
144 Value sux_phi = sux_state->stack_at(if_state->stack_size()); |
1899 | 145 if (sux_phi == NULL || sux_phi->as_Phi() == NULL || sux_phi->as_Phi()->block() != sux) return; |
4757
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
146 if (sux_phi->type()->size() != sux_state->stack_size() - if_state->stack_size()) return; |
0 | 147 |
1899 | 148 // get the values that were pushed in the true- and false-branch |
4757
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
149 Value t_value = t_goto->state()->stack_at(if_state->stack_size()); |
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
150 Value f_value = f_goto->state()->stack_at(if_state->stack_size()); |
1899 | 151 |
152 // backend does not support floats | |
153 assert(t_value->type()->base() == f_value->type()->base(), "incompatible types"); | |
154 if (t_value->type()->is_float_kind()) return; | |
0 | 155 |
1899 | 156 // check that successor has no other phi functions but sux_phi |
157 // this can happen when t_block or f_block contained additonal stores to local variables | |
158 // that are no longer represented by explicit instructions | |
159 for_each_phi_fun(sux, phi, | |
160 if (phi != sux_phi) return; | |
161 ); | |
162 // true and false blocks can't have phis | |
163 for_each_phi_fun(t_block, phi, return; ); | |
164 for_each_phi_fun(f_block, phi, return; ); | |
165 | |
166 // 2) substitute conditional expression | |
167 // with an IfOp followed by a Goto | |
168 // cut if_ away and get node before | |
169 Instruction* cur_end = if_->prev(block); | |
0 | 170 |
1899 | 171 // append constants of true- and false-block if necessary |
172 // clone constants because original block must not be destroyed | |
173 assert((t_value != f_const && f_value != t_const) || t_const == f_const, "mismatch"); | |
174 if (t_value == t_const) { | |
175 t_value = new Constant(t_const->type()); | |
176 NOT_PRODUCT(t_value->set_printable_bci(if_->printable_bci())); | |
177 cur_end = cur_end->set_next(t_value); | |
178 } | |
179 if (f_value == f_const) { | |
180 f_value = new Constant(f_const->type()); | |
181 NOT_PRODUCT(f_value->set_printable_bci(if_->printable_bci())); | |
182 cur_end = cur_end->set_next(f_value); | |
183 } | |
0 | 184 |
1899 | 185 Value result = make_ifop(if_->x(), if_->cond(), if_->y(), t_value, f_value); |
186 assert(result != NULL, "make_ifop must return a non-null instruction"); | |
187 if (!result->is_linked() && result->can_be_linked()) { | |
1819 | 188 NOT_PRODUCT(result->set_printable_bci(if_->printable_bci())); |
189 cur_end = cur_end->set_next(result); | |
1899 | 190 } |
0 | 191 |
1899 | 192 // append Goto to successor |
193 ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL; | |
194 Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint()); | |
195 | |
196 // prepare state for Goto | |
4757
7bca37d28f32
7114106: C1: assert(goto_state->is_same(sux_state)) failed: states must match now
roland
parents:
3792
diff
changeset
|
197 ValueStack* goto_state = if_state; |
1899 | 198 goto_state = goto_state->copy(ValueStack::StateAfter, goto_state->bci()); |
199 goto_state->push(result->type(), result); | |
200 assert(goto_state->is_same(sux_state), "states must match now"); | |
201 goto_->set_state(goto_state); | |
202 | |
203 cur_end = cur_end->set_next(goto_, goto_state->bci()); | |
204 | |
205 // Adjust control flow graph | |
206 BlockBegin::disconnect_edge(block, t_block); | |
207 BlockBegin::disconnect_edge(block, f_block); | |
208 if (t_block->number_of_preds() == 0) { | |
209 BlockBegin::disconnect_edge(t_block, sux); | |
210 } | |
211 adjust_exception_edges(block, t_block); | |
212 if (f_block->number_of_preds() == 0) { | |
213 BlockBegin::disconnect_edge(f_block, sux); | |
214 } | |
215 adjust_exception_edges(block, f_block); | |
216 | |
217 // update block end | |
218 block->set_end(goto_); | |
219 | |
220 // substitute the phi if possible | |
221 if (sux_phi->as_Phi()->operand_count() == 1) { | |
222 assert(sux_phi->as_Phi()->operand_at(0) == result, "screwed up phi"); | |
223 sux_phi->set_subst(result); | |
224 _has_substitution = true; | |
225 } | |
226 | |
227 // 3) successfully eliminated a conditional expression | |
228 _cee_count++; | |
229 if (PrintCEE) { | |
230 tty->print_cr("%d. CEE in B%d (B%d B%d)", cee_count(), block->block_id(), t_block->block_id(), f_block->block_id()); | |
231 tty->print_cr("%d. IfOp in B%d", ifop_count(), block->block_id()); | |
232 } | |
0 | 233 |
1899 | 234 _hir->verify(); |
235 } | |
236 | |
237 Value CE_Eliminator::make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval) { | |
238 if (!OptimizeIfOps) { | |
239 return new IfOp(x, cond, y, tval, fval); | |
240 } | |
241 | |
242 tval = tval->subst(); | |
243 fval = fval->subst(); | |
244 if (tval == fval) { | |
245 _ifop_count++; | |
246 return tval; | |
247 } | |
248 | |
249 x = x->subst(); | |
250 y = y->subst(); | |
251 | |
252 Constant* y_const = y->as_Constant(); | |
253 if (y_const != NULL) { | |
254 IfOp* x_ifop = x->as_IfOp(); | |
255 if (x_ifop != NULL) { // x is an ifop, y is a constant | |
256 Constant* x_tval_const = x_ifop->tval()->subst()->as_Constant(); | |
257 Constant* x_fval_const = x_ifop->fval()->subst()->as_Constant(); | |
0 | 258 |
1899 | 259 if (x_tval_const != NULL && x_fval_const != NULL) { |
260 Instruction::Condition x_ifop_cond = x_ifop->cond(); | |
261 | |
262 Constant::CompareResult t_compare_res = x_tval_const->compare(cond, y_const); | |
263 Constant::CompareResult f_compare_res = x_fval_const->compare(cond, y_const); | |
264 | |
3362
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
265 // not_comparable here is a valid return in case we're comparing unloaded oop constants |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
266 if (t_compare_res != Constant::not_comparable && f_compare_res != Constant::not_comparable) { |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
267 Value new_tval = t_compare_res == Constant::cond_true ? tval : fval; |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
268 Value new_fval = f_compare_res == Constant::cond_true ? tval : fval; |
0 | 269 |
3362
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
270 _ifop_count++; |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
271 if (new_tval == new_fval) { |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
272 return new_tval; |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
273 } else { |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
274 return new IfOp(x_ifop->x(), x_ifop_cond, x_ifop->y(), new_tval, new_fval); |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
275 } |
1899 | 276 } |
277 } | |
278 } else { | |
279 Constant* x_const = x->as_Constant(); | |
280 if (x_const != NULL) { // x and y are constants | |
281 Constant::CompareResult x_compare_res = x_const->compare(cond, y_const); | |
3362
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
282 // not_comparable here is a valid return in case we're comparing unloaded oop constants |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
283 if (x_compare_res != Constant::not_comparable) { |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
284 _ifop_count++; |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
285 return x_compare_res == Constant::cond_true ? tval : fval; |
d4c1fbc3de95
7042153: guarantee(x_compare_res != Constant::not_comparable) failed: incomparable constants in IfOp
iveresov
parents:
2446
diff
changeset
|
286 } |
1899 | 287 } |
0 | 288 } |
289 } | |
1899 | 290 return new IfOp(x, cond, y, tval, fval); |
291 } | |
0 | 292 |
293 void Optimizer::eliminate_conditional_expressions() { | |
294 // find conditional expressions & replace them with IfOps | |
295 CE_Eliminator ce(ir()); | |
296 } | |
297 | |
298 class BlockMerger: public BlockClosure { | |
299 private: | |
300 IR* _hir; | |
301 int _merge_count; // the number of block pairs successfully merged | |
302 | |
303 public: | |
304 BlockMerger(IR* hir) | |
305 : _hir(hir) | |
306 , _merge_count(0) | |
307 { | |
308 _hir->iterate_preorder(this); | |
309 } | |
310 | |
311 bool try_merge(BlockBegin* block) { | |
312 BlockEnd* end = block->end(); | |
313 if (end->as_Goto() != NULL) { | |
314 assert(end->number_of_sux() == 1, "end must have exactly one successor"); | |
315 // Note: It would be sufficient to check for the number of successors (= 1) | |
316 // in order to decide if this block can be merged potentially. That | |
317 // would then also include switch statements w/ only a default case. | |
318 // However, in that case we would need to make sure the switch tag | |
319 // expression is executed if it can produce observable side effects. | |
320 // We should probably have the canonicalizer simplifying such switch | |
321 // statements and then we are sure we don't miss these merge opportunities | |
322 // here (was bug - gri 7/7/99). | |
323 BlockBegin* sux = end->default_sux(); | |
324 if (sux->number_of_preds() == 1 && !sux->is_entry_block() && !end->is_safepoint()) { | |
325 // merge the two blocks | |
326 | |
327 #ifdef ASSERT | |
328 // verify that state at the end of block and at the beginning of sux are equal | |
329 // no phi functions must be present at beginning of sux | |
330 ValueStack* sux_state = sux->state(); | |
331 ValueStack* end_state = end->state(); | |
1819 | 332 |
333 assert(end_state->scope() == sux_state->scope(), "scopes must match"); | |
0 | 334 assert(end_state->stack_size() == sux_state->stack_size(), "stack not equal"); |
335 assert(end_state->locals_size() == sux_state->locals_size(), "locals not equal"); | |
336 | |
337 int index; | |
338 Value sux_value; | |
339 for_each_stack_value(sux_state, index, sux_value) { | |
340 assert(sux_value == end_state->stack_at(index), "stack not equal"); | |
341 } | |
342 for_each_local_value(sux_state, index, sux_value) { | |
343 assert(sux_value == end_state->local_at(index), "locals not equal"); | |
344 } | |
345 assert(sux_state->caller_state() == end_state->caller_state(), "caller not equal"); | |
346 #endif | |
347 | |
348 // find instruction before end & append first instruction of sux block | |
349 Instruction* prev = end->prev(block); | |
350 Instruction* next = sux->next(); | |
351 assert(prev->as_BlockEnd() == NULL, "must not be a BlockEnd"); | |
1819 | 352 prev->set_next(next); |
0 | 353 sux->disconnect_from_graph(); |
354 block->set_end(sux->end()); | |
355 // add exception handlers of deleted block, if any | |
356 for (int k = 0; k < sux->number_of_exception_handlers(); k++) { | |
357 BlockBegin* xhandler = sux->exception_handler_at(k); | |
358 block->add_exception_handler(xhandler); | |
359 | |
360 // also substitute predecessor of exception handler | |
361 assert(xhandler->is_predecessor(sux), "missing predecessor"); | |
362 xhandler->remove_predecessor(sux); | |
363 if (!xhandler->is_predecessor(block)) { | |
364 xhandler->add_predecessor(block); | |
365 } | |
366 } | |
367 | |
368 // debugging output | |
369 _merge_count++; | |
370 if (PrintBlockElimination) { | |
371 tty->print_cr("%d. merged B%d & B%d (stack size = %d)", | |
372 _merge_count, block->block_id(), sux->block_id(), sux->state()->stack_size()); | |
373 } | |
374 | |
375 _hir->verify(); | |
376 | |
377 If* if_ = block->end()->as_If(); | |
378 if (if_) { | |
379 IfOp* ifop = if_->x()->as_IfOp(); | |
380 Constant* con = if_->y()->as_Constant(); | |
381 bool swapped = false; | |
382 if (!con || !ifop) { | |
383 ifop = if_->y()->as_IfOp(); | |
384 con = if_->x()->as_Constant(); | |
385 swapped = true; | |
386 } | |
387 if (con && ifop) { | |
388 Constant* tval = ifop->tval()->as_Constant(); | |
389 Constant* fval = ifop->fval()->as_Constant(); | |
390 if (tval && fval) { | |
391 // Find the instruction before if_, starting with ifop. | |
392 // When if_ and ifop are not in the same block, prev | |
393 // becomes NULL In such (rare) cases it is not | |
394 // profitable to perform the optimization. | |
395 Value prev = ifop; | |
396 while (prev != NULL && prev->next() != if_) { | |
397 prev = prev->next(); | |
398 } | |
399 | |
400 if (prev != NULL) { | |
401 Instruction::Condition cond = if_->cond(); | |
402 BlockBegin* tsux = if_->tsux(); | |
403 BlockBegin* fsux = if_->fsux(); | |
404 if (swapped) { | |
405 cond = Instruction::mirror(cond); | |
406 } | |
407 | |
408 BlockBegin* tblock = tval->compare(cond, con, tsux, fsux); | |
409 BlockBegin* fblock = fval->compare(cond, con, tsux, fsux); | |
410 if (tblock != fblock && !if_->is_safepoint()) { | |
411 If* newif = new If(ifop->x(), ifop->cond(), false, ifop->y(), | |
412 tblock, fblock, if_->state_before(), if_->is_safepoint()); | |
413 newif->set_state(if_->state()->copy()); | |
414 | |
415 assert(prev->next() == if_, "must be guaranteed by above search"); | |
1819 | 416 NOT_PRODUCT(newif->set_printable_bci(if_->printable_bci())); |
417 prev->set_next(newif); | |
0 | 418 block->set_end(newif); |
419 | |
420 _merge_count++; | |
421 if (PrintBlockElimination) { | |
422 tty->print_cr("%d. replaced If and IfOp at end of B%d with single If", _merge_count, block->block_id()); | |
423 } | |
424 | |
425 _hir->verify(); | |
426 } | |
427 } | |
428 } | |
429 } | |
430 } | |
431 | |
432 return true; | |
433 } | |
434 } | |
435 return false; | |
436 } | |
437 | |
438 virtual void block_do(BlockBegin* block) { | |
439 _hir->verify(); | |
440 // repeat since the same block may merge again | |
441 while (try_merge(block)) { | |
442 _hir->verify(); | |
443 } | |
444 } | |
445 }; | |
446 | |
447 | |
448 void Optimizer::eliminate_blocks() { | |
449 // merge blocks if possible | |
450 BlockMerger bm(ir()); | |
451 } | |
452 | |
453 | |
454 class NullCheckEliminator; | |
455 class NullCheckVisitor: public InstructionVisitor { | |
456 private: | |
457 NullCheckEliminator* _nce; | |
458 NullCheckEliminator* nce() { return _nce; } | |
459 | |
460 public: | |
461 NullCheckVisitor() {} | |
462 | |
463 void set_eliminator(NullCheckEliminator* nce) { _nce = nce; } | |
464 | |
465 void do_Phi (Phi* x); | |
466 void do_Local (Local* x); | |
467 void do_Constant (Constant* x); | |
468 void do_LoadField (LoadField* x); | |
469 void do_StoreField (StoreField* x); | |
470 void do_ArrayLength (ArrayLength* x); | |
471 void do_LoadIndexed (LoadIndexed* x); | |
472 void do_StoreIndexed (StoreIndexed* x); | |
473 void do_NegateOp (NegateOp* x); | |
474 void do_ArithmeticOp (ArithmeticOp* x); | |
475 void do_ShiftOp (ShiftOp* x); | |
476 void do_LogicOp (LogicOp* x); | |
477 void do_CompareOp (CompareOp* x); | |
478 void do_IfOp (IfOp* x); | |
479 void do_Convert (Convert* x); | |
480 void do_NullCheck (NullCheck* x); | |
6266
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
4966
diff
changeset
|
481 void do_TypeCast (TypeCast* x); |
0 | 482 void do_Invoke (Invoke* x); |
483 void do_NewInstance (NewInstance* x); | |
484 void do_NewTypeArray (NewTypeArray* x); | |
485 void do_NewObjectArray (NewObjectArray* x); | |
486 void do_NewMultiArray (NewMultiArray* x); | |
487 void do_CheckCast (CheckCast* x); | |
488 void do_InstanceOf (InstanceOf* x); | |
489 void do_MonitorEnter (MonitorEnter* x); | |
490 void do_MonitorExit (MonitorExit* x); | |
491 void do_Intrinsic (Intrinsic* x); | |
492 void do_BlockBegin (BlockBegin* x); | |
493 void do_Goto (Goto* x); | |
494 void do_If (If* x); | |
495 void do_IfInstanceOf (IfInstanceOf* x); | |
496 void do_TableSwitch (TableSwitch* x); | |
497 void do_LookupSwitch (LookupSwitch* x); | |
498 void do_Return (Return* x); | |
499 void do_Throw (Throw* x); | |
500 void do_Base (Base* x); | |
501 void do_OsrEntry (OsrEntry* x); | |
502 void do_ExceptionObject(ExceptionObject* x); | |
503 void do_RoundFP (RoundFP* x); | |
504 void do_UnsafeGetRaw (UnsafeGetRaw* x); | |
505 void do_UnsafePutRaw (UnsafePutRaw* x); | |
506 void do_UnsafeGetObject(UnsafeGetObject* x); | |
507 void do_UnsafePutObject(UnsafePutObject* x); | |
6795
7eca5de9e0b6
7023898: Intrinsify AtomicLongFieldUpdater.getAndIncrement()
roland
parents:
6266
diff
changeset
|
508 void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x); |
0 | 509 void do_UnsafePrefetchRead (UnsafePrefetchRead* x); |
510 void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); | |
511 void do_ProfileCall (ProfileCall* x); | |
1783 | 512 void do_ProfileInvoke (ProfileInvoke* x); |
2166
403dc4c1d7f5
6809483: hotspot:::method_entry are not correctly generated for "method()V"
never
parents:
1972
diff
changeset
|
513 void do_RuntimeCall (RuntimeCall* x); |
4966
701a83c86f28
7120481: storeStore barrier in constructor with final field
jiangli
parents:
4764
diff
changeset
|
514 void do_MemBar (MemBar* x); |
0 | 515 }; |
516 | |
517 | |
518 // Because of a static contained within (for the purpose of iteration | |
519 // over instructions), it is only valid to have one of these active at | |
520 // a time | |
1584 | 521 class NullCheckEliminator: public ValueVisitor { |
0 | 522 private: |
523 Optimizer* _opt; | |
524 | |
525 ValueSet* _visitable_instructions; // Visit each instruction only once per basic block | |
526 BlockList* _work_list; // Basic blocks to visit | |
527 | |
528 bool visitable(Value x) { | |
529 assert(_visitable_instructions != NULL, "check"); | |
530 return _visitable_instructions->contains(x); | |
531 } | |
532 void mark_visited(Value x) { | |
533 assert(_visitable_instructions != NULL, "check"); | |
534 _visitable_instructions->remove(x); | |
535 } | |
536 void mark_visitable(Value x) { | |
537 assert(_visitable_instructions != NULL, "check"); | |
538 _visitable_instructions->put(x); | |
539 } | |
540 void clear_visitable_state() { | |
541 assert(_visitable_instructions != NULL, "check"); | |
542 _visitable_instructions->clear(); | |
543 } | |
544 | |
545 ValueSet* _set; // current state, propagated to subsequent BlockBegins | |
546 ValueSetList _block_states; // BlockBegin null-check states for all processed blocks | |
547 NullCheckVisitor _visitor; | |
548 NullCheck* _last_explicit_null_check; | |
549 | |
550 bool set_contains(Value x) { assert(_set != NULL, "check"); return _set->contains(x); } | |
551 void set_put (Value x) { assert(_set != NULL, "check"); _set->put(x); } | |
552 void set_remove (Value x) { assert(_set != NULL, "check"); _set->remove(x); } | |
553 | |
554 BlockList* work_list() { return _work_list; } | |
555 | |
556 void iterate_all(); | |
557 void iterate_one(BlockBegin* block); | |
558 | |
559 ValueSet* state() { return _set; } | |
560 void set_state_from (ValueSet* state) { _set->set_from(state); } | |
561 ValueSet* state_for (BlockBegin* block) { return _block_states[block->block_id()]; } | |
562 void set_state_for (BlockBegin* block, ValueSet* stack) { _block_states[block->block_id()] = stack; } | |
563 // Returns true if caused a change in the block's state. | |
564 bool merge_state_for(BlockBegin* block, | |
565 ValueSet* incoming_state); | |
566 | |
567 public: | |
568 // constructor | |
569 NullCheckEliminator(Optimizer* opt) | |
570 : _opt(opt) | |
571 , _set(new ValueSet()) | |
572 , _last_explicit_null_check(NULL) | |
573 , _block_states(BlockBegin::number_of_blocks(), NULL) | |
574 , _work_list(new BlockList()) { | |
575 _visitable_instructions = new ValueSet(); | |
576 _visitor.set_eliminator(this); | |
577 } | |
578 | |
579 Optimizer* opt() { return _opt; } | |
580 IR* ir () { return opt()->ir(); } | |
581 | |
582 // Process a graph | |
583 void iterate(BlockBegin* root); | |
584 | |
1584 | 585 void visit(Value* f); |
586 | |
0 | 587 // In some situations (like NullCheck(x); getfield(x)) the debug |
588 // information from the explicit NullCheck can be used to populate | |
589 // the getfield, even if the two instructions are in different | |
590 // scopes; this allows implicit null checks to be used but the | |
591 // correct exception information to be generated. We must clear the | |
592 // last-traversed NullCheck when we reach a potentially-exception- | |
593 // throwing instruction, as well as in some other cases. | |
594 void set_last_explicit_null_check(NullCheck* check) { _last_explicit_null_check = check; } | |
595 NullCheck* last_explicit_null_check() { return _last_explicit_null_check; } | |
596 Value last_explicit_null_check_obj() { return (_last_explicit_null_check | |
597 ? _last_explicit_null_check->obj() | |
598 : NULL); } | |
599 NullCheck* consume_last_explicit_null_check() { | |
600 _last_explicit_null_check->unpin(Instruction::PinExplicitNullCheck); | |
601 _last_explicit_null_check->set_can_trap(false); | |
602 return _last_explicit_null_check; | |
603 } | |
604 void clear_last_explicit_null_check() { _last_explicit_null_check = NULL; } | |
605 | |
606 // Handlers for relevant instructions | |
607 // (separated out from NullCheckVisitor for clarity) | |
608 | |
609 // The basic contract is that these must leave the instruction in | |
610 // the desired state; must not assume anything about the state of | |
611 // the instruction. We make multiple passes over some basic blocks | |
612 // and the last pass is the only one whose result is valid. | |
613 void handle_AccessField (AccessField* x); | |
614 void handle_ArrayLength (ArrayLength* x); | |
615 void handle_LoadIndexed (LoadIndexed* x); | |
616 void handle_StoreIndexed (StoreIndexed* x); | |
617 void handle_NullCheck (NullCheck* x); | |
618 void handle_Invoke (Invoke* x); | |
619 void handle_NewInstance (NewInstance* x); | |
620 void handle_NewArray (NewArray* x); | |
621 void handle_AccessMonitor (AccessMonitor* x); | |
622 void handle_Intrinsic (Intrinsic* x); | |
623 void handle_ExceptionObject (ExceptionObject* x); | |
624 void handle_Phi (Phi* x); | |
625 }; | |
626 | |
627 | |
628 // NEEDS_CLEANUP | |
629 // There may be other instructions which need to clear the last | |
630 // explicit null check. Anything across which we can not hoist the | |
631 // debug information for a NullCheck instruction must clear it. It | |
632 // might be safer to pattern match "NullCheck ; {AccessField, | |
633 // ArrayLength, LoadIndexed}" but it is more easily structured this way. | |
634 // Should test to see performance hit of clearing it for all handlers | |
635 // with empty bodies below. If it is negligible then we should leave | |
636 // that in for safety, otherwise should think more about it. | |
637 void NullCheckVisitor::do_Phi (Phi* x) { nce()->handle_Phi(x); } | |
638 void NullCheckVisitor::do_Local (Local* x) {} | |
639 void NullCheckVisitor::do_Constant (Constant* x) { /* FIXME: handle object constants */ } | |
640 void NullCheckVisitor::do_LoadField (LoadField* x) { nce()->handle_AccessField(x); } | |
641 void NullCheckVisitor::do_StoreField (StoreField* x) { nce()->handle_AccessField(x); } | |
642 void NullCheckVisitor::do_ArrayLength (ArrayLength* x) { nce()->handle_ArrayLength(x); } | |
643 void NullCheckVisitor::do_LoadIndexed (LoadIndexed* x) { nce()->handle_LoadIndexed(x); } | |
644 void NullCheckVisitor::do_StoreIndexed (StoreIndexed* x) { nce()->handle_StoreIndexed(x); } | |
645 void NullCheckVisitor::do_NegateOp (NegateOp* x) {} | |
646 void NullCheckVisitor::do_ArithmeticOp (ArithmeticOp* x) { if (x->can_trap()) nce()->clear_last_explicit_null_check(); } | |
647 void NullCheckVisitor::do_ShiftOp (ShiftOp* x) {} | |
648 void NullCheckVisitor::do_LogicOp (LogicOp* x) {} | |
649 void NullCheckVisitor::do_CompareOp (CompareOp* x) {} | |
650 void NullCheckVisitor::do_IfOp (IfOp* x) {} | |
651 void NullCheckVisitor::do_Convert (Convert* x) {} | |
652 void NullCheckVisitor::do_NullCheck (NullCheck* x) { nce()->handle_NullCheck(x); } | |
6266
1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
twisti
parents:
4966
diff
changeset
|
653 void NullCheckVisitor::do_TypeCast (TypeCast* x) {} |
0 | 654 void NullCheckVisitor::do_Invoke (Invoke* x) { nce()->handle_Invoke(x); } |
655 void NullCheckVisitor::do_NewInstance (NewInstance* x) { nce()->handle_NewInstance(x); } | |
656 void NullCheckVisitor::do_NewTypeArray (NewTypeArray* x) { nce()->handle_NewArray(x); } | |
657 void NullCheckVisitor::do_NewObjectArray (NewObjectArray* x) { nce()->handle_NewArray(x); } | |
658 void NullCheckVisitor::do_NewMultiArray (NewMultiArray* x) { nce()->handle_NewArray(x); } | |
3792
15559220ce79
6478991: C1 NullCheckEliminator yields incorrect exceptions
never
parents:
3362
diff
changeset
|
659 void NullCheckVisitor::do_CheckCast (CheckCast* x) { nce()->clear_last_explicit_null_check(); } |
0 | 660 void NullCheckVisitor::do_InstanceOf (InstanceOf* x) {} |
661 void NullCheckVisitor::do_MonitorEnter (MonitorEnter* x) { nce()->handle_AccessMonitor(x); } | |
662 void NullCheckVisitor::do_MonitorExit (MonitorExit* x) { nce()->handle_AccessMonitor(x); } | |
2446 | 663 void NullCheckVisitor::do_Intrinsic (Intrinsic* x) { nce()->handle_Intrinsic(x); } |
0 | 664 void NullCheckVisitor::do_BlockBegin (BlockBegin* x) {} |
665 void NullCheckVisitor::do_Goto (Goto* x) {} | |
666 void NullCheckVisitor::do_If (If* x) {} | |
667 void NullCheckVisitor::do_IfInstanceOf (IfInstanceOf* x) {} | |
668 void NullCheckVisitor::do_TableSwitch (TableSwitch* x) {} | |
669 void NullCheckVisitor::do_LookupSwitch (LookupSwitch* x) {} | |
670 void NullCheckVisitor::do_Return (Return* x) {} | |
671 void NullCheckVisitor::do_Throw (Throw* x) { nce()->clear_last_explicit_null_check(); } | |
672 void NullCheckVisitor::do_Base (Base* x) {} | |
673 void NullCheckVisitor::do_OsrEntry (OsrEntry* x) {} | |
674 void NullCheckVisitor::do_ExceptionObject(ExceptionObject* x) { nce()->handle_ExceptionObject(x); } | |
675 void NullCheckVisitor::do_RoundFP (RoundFP* x) {} | |
676 void NullCheckVisitor::do_UnsafeGetRaw (UnsafeGetRaw* x) {} | |
677 void NullCheckVisitor::do_UnsafePutRaw (UnsafePutRaw* x) {} | |
678 void NullCheckVisitor::do_UnsafeGetObject(UnsafeGetObject* x) {} | |
679 void NullCheckVisitor::do_UnsafePutObject(UnsafePutObject* x) {} | |
6795
7eca5de9e0b6
7023898: Intrinsify AtomicLongFieldUpdater.getAndIncrement()
roland
parents:
6266
diff
changeset
|
680 void NullCheckVisitor::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {} |
0 | 681 void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {} |
682 void NullCheckVisitor::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {} | |
683 void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check(); } | |
1783 | 684 void NullCheckVisitor::do_ProfileInvoke (ProfileInvoke* x) {} |
2166
403dc4c1d7f5
6809483: hotspot:::method_entry are not correctly generated for "method()V"
never
parents:
1972
diff
changeset
|
685 void NullCheckVisitor::do_RuntimeCall (RuntimeCall* x) {} |
4966
701a83c86f28
7120481: storeStore barrier in constructor with final field
jiangli
parents:
4764
diff
changeset
|
686 void NullCheckVisitor::do_MemBar (MemBar* x) {} |
0 | 687 |
688 | |
1584 | 689 void NullCheckEliminator::visit(Value* p) { |
0 | 690 assert(*p != NULL, "should not find NULL instructions"); |
1584 | 691 if (visitable(*p)) { |
692 mark_visited(*p); | |
693 (*p)->visit(&_visitor); | |
0 | 694 } |
695 } | |
696 | |
697 bool NullCheckEliminator::merge_state_for(BlockBegin* block, ValueSet* incoming_state) { | |
698 ValueSet* state = state_for(block); | |
699 if (state == NULL) { | |
700 state = incoming_state->copy(); | |
701 set_state_for(block, state); | |
702 return true; | |
703 } else { | |
704 bool changed = state->set_intersect(incoming_state); | |
705 if (PrintNullCheckElimination && changed) { | |
706 tty->print_cr("Block %d's null check state changed", block->block_id()); | |
707 } | |
708 return changed; | |
709 } | |
710 } | |
711 | |
712 | |
713 void NullCheckEliminator::iterate_all() { | |
714 while (work_list()->length() > 0) { | |
715 iterate_one(work_list()->pop()); | |
716 } | |
717 } | |
718 | |
719 | |
720 void NullCheckEliminator::iterate_one(BlockBegin* block) { | |
721 clear_visitable_state(); | |
722 // clear out an old explicit null checks | |
723 set_last_explicit_null_check(NULL); | |
724 | |
725 if (PrintNullCheckElimination) { | |
726 tty->print_cr(" ...iterating block %d in null check elimination for %s::%s%s", | |
727 block->block_id(), | |
728 ir()->method()->holder()->name()->as_utf8(), | |
729 ir()->method()->name()->as_utf8(), | |
730 ir()->method()->signature()->as_symbol()->as_utf8()); | |
731 } | |
732 | |
733 // Create new state if none present (only happens at root) | |
734 if (state_for(block) == NULL) { | |
735 ValueSet* tmp_state = new ValueSet(); | |
736 set_state_for(block, tmp_state); | |
737 // Initial state is that local 0 (receiver) is non-null for | |
738 // non-static methods | |
739 ValueStack* stack = block->state(); | |
740 IRScope* scope = stack->scope(); | |
741 ciMethod* method = scope->method(); | |
742 if (!method->is_static()) { | |
743 Local* local0 = stack->local_at(0)->as_Local(); | |
744 assert(local0 != NULL, "must be"); | |
745 assert(local0->type() == objectType, "invalid type of receiver"); | |
746 | |
747 if (local0 != NULL) { | |
748 // Local 0 is used in this scope | |
749 tmp_state->put(local0); | |
750 if (PrintNullCheckElimination) { | |
751 tty->print_cr("Local 0 (value %d) proven non-null upon entry", local0->id()); | |
752 } | |
753 } | |
754 } | |
755 } | |
756 | |
757 // Must copy block's state to avoid mutating it during iteration | |
758 // through the block -- otherwise "not-null" states can accidentally | |
759 // propagate "up" through the block during processing of backward | |
760 // branches and algorithm is incorrect (and does not converge) | |
761 set_state_from(state_for(block)); | |
762 | |
763 // allow visiting of Phis belonging to this block | |
764 for_each_phi_fun(block, phi, | |
765 mark_visitable(phi); | |
766 ); | |
767 | |
768 BlockEnd* e = block->end(); | |
769 assert(e != NULL, "incomplete graph"); | |
770 int i; | |
771 | |
772 // Propagate the state before this block into the exception | |
773 // handlers. They aren't true successors since we aren't guaranteed | |
774 // to execute the whole block before executing them. Also putting | |
775 // them on first seems to help reduce the amount of iteration to | |
776 // reach a fixed point. | |
777 for (i = 0; i < block->number_of_exception_handlers(); i++) { | |
778 BlockBegin* next = block->exception_handler_at(i); | |
779 if (merge_state_for(next, state())) { | |
780 if (!work_list()->contains(next)) { | |
781 work_list()->push(next); | |
782 } | |
783 } | |
784 } | |
785 | |
786 // Iterate through block, updating state. | |
787 for (Instruction* instr = block; instr != NULL; instr = instr->next()) { | |
788 // Mark instructions in this block as visitable as they are seen | |
789 // in the instruction list. This keeps the iteration from | |
790 // visiting instructions which are references in other blocks or | |
791 // visiting instructions more than once. | |
792 mark_visitable(instr); | |
1819 | 793 if (instr->is_pinned() || instr->can_trap() || (instr->as_NullCheck() != NULL)) { |
0 | 794 mark_visited(instr); |
1584 | 795 instr->input_values_do(this); |
0 | 796 instr->visit(&_visitor); |
797 } | |
798 } | |
799 | |
800 // Propagate state to successors if necessary | |
801 for (i = 0; i < e->number_of_sux(); i++) { | |
802 BlockBegin* next = e->sux_at(i); | |
803 if (merge_state_for(next, state())) { | |
804 if (!work_list()->contains(next)) { | |
805 work_list()->push(next); | |
806 } | |
807 } | |
808 } | |
809 } | |
810 | |
811 | |
812 void NullCheckEliminator::iterate(BlockBegin* block) { | |
813 work_list()->push(block); | |
814 iterate_all(); | |
815 } | |
816 | |
817 void NullCheckEliminator::handle_AccessField(AccessField* x) { | |
818 if (x->is_static()) { | |
819 if (x->as_LoadField() != NULL) { | |
820 // If the field is a non-null static final object field (as is | |
821 // often the case for sun.misc.Unsafe), put this LoadField into | |
822 // the non-null map | |
823 ciField* field = x->field(); | |
824 if (field->is_constant()) { | |
825 ciConstant field_val = field->constant_value(); | |
826 BasicType field_type = field_val.basic_type(); | |
827 if (field_type == T_OBJECT || field_type == T_ARRAY) { | |
828 ciObject* obj_val = field_val.as_object(); | |
829 if (!obj_val->is_null_object()) { | |
830 if (PrintNullCheckElimination) { | |
831 tty->print_cr("AccessField %d proven non-null by static final non-null oop check", | |
832 x->id()); | |
833 } | |
834 set_put(x); | |
835 } | |
836 } | |
837 } | |
838 } | |
839 // Be conservative | |
840 clear_last_explicit_null_check(); | |
841 return; | |
842 } | |
843 | |
844 Value obj = x->obj(); | |
845 if (set_contains(obj)) { | |
846 // Value is non-null => update AccessField | |
847 if (last_explicit_null_check_obj() == obj && !x->needs_patching()) { | |
848 x->set_explicit_null_check(consume_last_explicit_null_check()); | |
849 x->set_needs_null_check(true); | |
850 if (PrintNullCheckElimination) { | |
851 tty->print_cr("Folded NullCheck %d into AccessField %d's null check for value %d", | |
852 x->explicit_null_check()->id(), x->id(), obj->id()); | |
853 } | |
854 } else { | |
855 x->set_explicit_null_check(NULL); | |
856 x->set_needs_null_check(false); | |
857 if (PrintNullCheckElimination) { | |
858 tty->print_cr("Eliminated AccessField %d's null check for value %d", x->id(), obj->id()); | |
859 } | |
860 } | |
861 } else { | |
862 set_put(obj); | |
863 if (PrintNullCheckElimination) { | |
864 tty->print_cr("AccessField %d of value %d proves value to be non-null", x->id(), obj->id()); | |
865 } | |
866 // Ensure previous passes do not cause wrong state | |
867 x->set_needs_null_check(true); | |
868 x->set_explicit_null_check(NULL); | |
869 } | |
870 clear_last_explicit_null_check(); | |
871 } | |
872 | |
873 | |
874 void NullCheckEliminator::handle_ArrayLength(ArrayLength* x) { | |
875 Value array = x->array(); | |
876 if (set_contains(array)) { | |
877 // Value is non-null => update AccessArray | |
878 if (last_explicit_null_check_obj() == array) { | |
879 x->set_explicit_null_check(consume_last_explicit_null_check()); | |
880 x->set_needs_null_check(true); | |
881 if (PrintNullCheckElimination) { | |
882 tty->print_cr("Folded NullCheck %d into ArrayLength %d's null check for value %d", | |
883 x->explicit_null_check()->id(), x->id(), array->id()); | |
884 } | |
885 } else { | |
886 x->set_explicit_null_check(NULL); | |
887 x->set_needs_null_check(false); | |
888 if (PrintNullCheckElimination) { | |
889 tty->print_cr("Eliminated ArrayLength %d's null check for value %d", x->id(), array->id()); | |
890 } | |
891 } | |
892 } else { | |
893 set_put(array); | |
894 if (PrintNullCheckElimination) { | |
895 tty->print_cr("ArrayLength %d of value %d proves value to be non-null", x->id(), array->id()); | |
896 } | |
897 // Ensure previous passes do not cause wrong state | |
898 x->set_needs_null_check(true); | |
899 x->set_explicit_null_check(NULL); | |
900 } | |
901 clear_last_explicit_null_check(); | |
902 } | |
903 | |
904 | |
905 void NullCheckEliminator::handle_LoadIndexed(LoadIndexed* x) { | |
906 Value array = x->array(); | |
907 if (set_contains(array)) { | |
908 // Value is non-null => update AccessArray | |
909 if (last_explicit_null_check_obj() == array) { | |
910 x->set_explicit_null_check(consume_last_explicit_null_check()); | |
911 x->set_needs_null_check(true); | |
912 if (PrintNullCheckElimination) { | |
913 tty->print_cr("Folded NullCheck %d into LoadIndexed %d's null check for value %d", | |
914 x->explicit_null_check()->id(), x->id(), array->id()); | |
915 } | |
916 } else { | |
917 x->set_explicit_null_check(NULL); | |
918 x->set_needs_null_check(false); | |
919 if (PrintNullCheckElimination) { | |
920 tty->print_cr("Eliminated LoadIndexed %d's null check for value %d", x->id(), array->id()); | |
921 } | |
922 } | |
923 } else { | |
924 set_put(array); | |
925 if (PrintNullCheckElimination) { | |
926 tty->print_cr("LoadIndexed %d of value %d proves value to be non-null", x->id(), array->id()); | |
927 } | |
928 // Ensure previous passes do not cause wrong state | |
929 x->set_needs_null_check(true); | |
930 x->set_explicit_null_check(NULL); | |
931 } | |
932 clear_last_explicit_null_check(); | |
933 } | |
934 | |
935 | |
936 void NullCheckEliminator::handle_StoreIndexed(StoreIndexed* x) { | |
937 Value array = x->array(); | |
938 if (set_contains(array)) { | |
939 // Value is non-null => update AccessArray | |
940 if (PrintNullCheckElimination) { | |
941 tty->print_cr("Eliminated StoreIndexed %d's null check for value %d", x->id(), array->id()); | |
942 } | |
943 x->set_needs_null_check(false); | |
944 } else { | |
945 set_put(array); | |
946 if (PrintNullCheckElimination) { | |
947 tty->print_cr("StoreIndexed %d of value %d proves value to be non-null", x->id(), array->id()); | |
948 } | |
949 // Ensure previous passes do not cause wrong state | |
950 x->set_needs_null_check(true); | |
951 } | |
952 clear_last_explicit_null_check(); | |
953 } | |
954 | |
955 | |
956 void NullCheckEliminator::handle_NullCheck(NullCheck* x) { | |
957 Value obj = x->obj(); | |
958 if (set_contains(obj)) { | |
959 // Already proven to be non-null => this NullCheck is useless | |
960 if (PrintNullCheckElimination) { | |
961 tty->print_cr("Eliminated NullCheck %d for value %d", x->id(), obj->id()); | |
962 } | |
963 // Don't unpin since that may shrink obj's live range and make it unavailable for debug info. | |
964 // The code generator won't emit LIR for a NullCheck that cannot trap. | |
965 x->set_can_trap(false); | |
966 } else { | |
967 // May be null => add to map and set last explicit NullCheck | |
968 x->set_can_trap(true); | |
969 // make sure it's pinned if it can trap | |
970 x->pin(Instruction::PinExplicitNullCheck); | |
971 set_put(obj); | |
972 set_last_explicit_null_check(x); | |
973 if (PrintNullCheckElimination) { | |
974 tty->print_cr("NullCheck %d of value %d proves value to be non-null", x->id(), obj->id()); | |
975 } | |
976 } | |
977 } | |
978 | |
979 | |
980 void NullCheckEliminator::handle_Invoke(Invoke* x) { | |
981 if (!x->has_receiver()) { | |
982 // Be conservative | |
983 clear_last_explicit_null_check(); | |
984 return; | |
985 } | |
986 | |
987 Value recv = x->receiver(); | |
988 if (!set_contains(recv)) { | |
989 set_put(recv); | |
990 if (PrintNullCheckElimination) { | |
991 tty->print_cr("Invoke %d of value %d proves value to be non-null", x->id(), recv->id()); | |
992 } | |
993 } | |
994 clear_last_explicit_null_check(); | |
995 } | |
996 | |
997 | |
998 void NullCheckEliminator::handle_NewInstance(NewInstance* x) { | |
999 set_put(x); | |
1000 if (PrintNullCheckElimination) { | |
1001 tty->print_cr("NewInstance %d is non-null", x->id()); | |
1002 } | |
1003 } | |
1004 | |
1005 | |
1006 void NullCheckEliminator::handle_NewArray(NewArray* x) { | |
1007 set_put(x); | |
1008 if (PrintNullCheckElimination) { | |
1009 tty->print_cr("NewArray %d is non-null", x->id()); | |
1010 } | |
1011 } | |
1012 | |
1013 | |
1014 void NullCheckEliminator::handle_ExceptionObject(ExceptionObject* x) { | |
1015 set_put(x); | |
1016 if (PrintNullCheckElimination) { | |
1017 tty->print_cr("ExceptionObject %d is non-null", x->id()); | |
1018 } | |
1019 } | |
1020 | |
1021 | |
1022 void NullCheckEliminator::handle_AccessMonitor(AccessMonitor* x) { | |
1023 Value obj = x->obj(); | |
1024 if (set_contains(obj)) { | |
1025 // Value is non-null => update AccessMonitor | |
1026 if (PrintNullCheckElimination) { | |
1027 tty->print_cr("Eliminated AccessMonitor %d's null check for value %d", x->id(), obj->id()); | |
1028 } | |
1029 x->set_needs_null_check(false); | |
1030 } else { | |
1031 set_put(obj); | |
1032 if (PrintNullCheckElimination) { | |
1033 tty->print_cr("AccessMonitor %d of value %d proves value to be non-null", x->id(), obj->id()); | |
1034 } | |
1035 // Ensure previous passes do not cause wrong state | |
1036 x->set_needs_null_check(true); | |
1037 } | |
1038 clear_last_explicit_null_check(); | |
1039 } | |
1040 | |
1041 | |
1042 void NullCheckEliminator::handle_Intrinsic(Intrinsic* x) { | |
1043 if (!x->has_receiver()) { | |
2446 | 1044 if (x->id() == vmIntrinsics::_arraycopy) { |
1045 for (int i = 0; i < x->number_of_arguments(); i++) { | |
1046 x->set_arg_needs_null_check(i, !set_contains(x->argument_at(i))); | |
1047 } | |
1048 } | |
1049 | |
0 | 1050 // Be conservative |
1051 clear_last_explicit_null_check(); | |
1052 return; | |
1053 } | |
1054 | |
1055 Value recv = x->receiver(); | |
1056 if (set_contains(recv)) { | |
1057 // Value is non-null => update Intrinsic | |
1058 if (PrintNullCheckElimination) { | |
1059 tty->print_cr("Eliminated Intrinsic %d's null check for value %d", x->id(), recv->id()); | |
1060 } | |
1061 x->set_needs_null_check(false); | |
1062 } else { | |
1063 set_put(recv); | |
1064 if (PrintNullCheckElimination) { | |
1065 tty->print_cr("Intrinsic %d of value %d proves value to be non-null", x->id(), recv->id()); | |
1066 } | |
1067 // Ensure previous passes do not cause wrong state | |
1068 x->set_needs_null_check(true); | |
1069 } | |
1070 clear_last_explicit_null_check(); | |
1071 } | |
1072 | |
1073 | |
1074 void NullCheckEliminator::handle_Phi(Phi* x) { | |
1075 int i; | |
1076 bool all_non_null = true; | |
1077 if (x->is_illegal()) { | |
1078 all_non_null = false; | |
1079 } else { | |
1080 for (i = 0; i < x->operand_count(); i++) { | |
1081 Value input = x->operand_at(i); | |
1082 if (!set_contains(input)) { | |
1083 all_non_null = false; | |
1084 } | |
1085 } | |
1086 } | |
1087 | |
1088 if (all_non_null) { | |
1089 // Value is non-null => update Phi | |
1090 if (PrintNullCheckElimination) { | |
1091 tty->print_cr("Eliminated Phi %d's null check for phifun because all inputs are non-null", x->id()); | |
1092 } | |
1093 x->set_needs_null_check(false); | |
1094 } else if (set_contains(x)) { | |
1095 set_remove(x); | |
1096 } | |
1097 } | |
1098 | |
1099 | |
1100 void Optimizer::eliminate_null_checks() { | |
1101 ResourceMark rm; | |
1102 | |
1103 NullCheckEliminator nce(this); | |
1104 | |
1105 if (PrintNullCheckElimination) { | |
1106 tty->print_cr("Starting null check elimination for method %s::%s%s", | |
1107 ir()->method()->holder()->name()->as_utf8(), | |
1108 ir()->method()->name()->as_utf8(), | |
1109 ir()->method()->signature()->as_symbol()->as_utf8()); | |
1110 } | |
1111 | |
1112 // Apply to graph | |
1113 nce.iterate(ir()->start()); | |
1114 | |
1115 // walk over the graph looking for exception | |
1116 // handlers and iterate over them as well | |
1117 int nblocks = BlockBegin::number_of_blocks(); | |
1118 BlockList blocks(nblocks); | |
1119 boolArray visited_block(nblocks, false); | |
1120 | |
1121 blocks.push(ir()->start()); | |
1122 visited_block[ir()->start()->block_id()] = true; | |
1123 for (int i = 0; i < blocks.length(); i++) { | |
1124 BlockBegin* b = blocks[i]; | |
1125 // exception handlers need to be treated as additional roots | |
1126 for (int e = b->number_of_exception_handlers(); e-- > 0; ) { | |
1127 BlockBegin* excp = b->exception_handler_at(e); | |
1128 int id = excp->block_id(); | |
1129 if (!visited_block[id]) { | |
1130 blocks.push(excp); | |
1131 visited_block[id] = true; | |
1132 nce.iterate(excp); | |
1133 } | |
1134 } | |
1135 // traverse successors | |
1136 BlockEnd *end = b->end(); | |
1137 for (int s = end->number_of_sux(); s-- > 0; ) { | |
1138 BlockBegin* next = end->sux_at(s); | |
1139 int id = next->block_id(); | |
1140 if (!visited_block[id]) { | |
1141 blocks.push(next); | |
1142 visited_block[id] = true; | |
1143 } | |
1144 } | |
1145 } | |
1146 | |
1147 | |
1148 if (PrintNullCheckElimination) { | |
1149 tty->print_cr("Done with null check elimination for method %s::%s%s", | |
1150 ir()->method()->holder()->name()->as_utf8(), | |
1151 ir()->method()->name()->as_utf8(), | |
1152 ir()->method()->signature()->as_symbol()->as_utf8()); | |
1153 } | |
1154 } |