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