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