/* * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// ------------------------------------------------------------------ // ciMethodBlocks::split_block_at // // Split the block spanning bci into two separate ranges. The former // block becomes the second half and a new range is created for the // first half. Returns the range beginning at bci.
ciBlock *ciMethodBlocks::split_block_at(int bci) {
ciBlock *former_block = block_containing(bci);
ciBlock *new_block = new(_arena) ciBlock(_method, _num_blocks++, former_block->start_bci());
_blocks->append(new_block);
assert(former_block != NULL, "must not be NULL");
new_block->set_limit_bci(bci);
former_block->set_start_bci(bci); for (int pos=bci-1; pos >= 0; pos--) {
ciBlock *current_block = block_containing(pos); if (current_block == former_block) { // Replace it.
_bci_to_block[pos] = new_block;
} elseif (current_block == NULL) { // Non-bytecode start. Skip. continue;
} else { // We are done with our backwards walk break;
}
} // Move an exception handler information if needed. if (former_block->is_handler()) { int ex_start = former_block->ex_start_bci(); int ex_end = former_block->ex_limit_bci();
new_block->set_exception_range(ex_start, ex_end); // Clear information in former_block.
former_block->clear_exception_handler();
} return former_block;
}
ciBlock *ciMethodBlocks::make_block_at(int bci) {
ciBlock *cb = block_containing(bci); if (cb == NULL ) { // This is our first time visiting this bytecode. Create // a fresh block and assign it this starting point.
ciBlock *nb = new(_arena) ciBlock(_method, _num_blocks++, bci);
_blocks->append(nb);
_bci_to_block[bci] = nb; return nb;
} elseif (cb->start_bci() == bci) { // The block begins at bci. Simply return it. return cb;
} else { // We have already created a block containing bci but // not starting at bci. This existing block needs to // be split into two. return split_block_at(bci);
}
}
while (s.next() != ciBytecodeStream::EOBC()) { int bci = s.cur_bci(); // Determine if a new block has been made at the current bci. If // this block differs from our current range, switch to the new // one and end the old one.
assert(cur_block != NULL, "must always have a current block");
ciBlock *new_block = block_containing(bci); if (new_block == NULL || new_block == cur_block) { // We have not marked this bci as the start of a new block. // Keep interpreting the current_range.
_bci_to_block[bci] = cur_block;
} else {
cur_block->set_limit_bci(bci);
cur_block = new_block;
}
switch (s.cur_bc()) { case Bytecodes::_ifeq : case Bytecodes::_ifne : case Bytecodes::_iflt : case Bytecodes::_ifge : case Bytecodes::_ifgt : case Bytecodes::_ifle : case Bytecodes::_if_icmpeq : case Bytecodes::_if_icmpne : case Bytecodes::_if_icmplt : case Bytecodes::_if_icmpge : case Bytecodes::_if_icmpgt : case Bytecodes::_if_icmple : case Bytecodes::_if_acmpeq : case Bytecodes::_if_acmpne : case Bytecodes::_ifnull : case Bytecodes::_ifnonnull :
{
cur_block->set_control_bci(bci); if (s.next_bci() < limit_bci) {
ciBlock *fall_through = make_block_at(s.next_bci());
} int dest_bci = s.get_dest();
ciBlock *dest = make_block_at(dest_bci); break;
}
case Bytecodes::_goto :
{
cur_block->set_control_bci(bci); if (s.next_bci() < limit_bci) {
(void) make_block_at(s.next_bci());
} int dest_bci = s.get_dest();
ciBlock *dest = make_block_at(dest_bci); break;
}
case Bytecodes::_jsr :
{
cur_block->set_control_bci(bci); if (s.next_bci() < limit_bci) {
ciBlock *ret = make_block_at(s.next_bci());
} int dest_bci = s.get_dest();
ciBlock *dest = make_block_at(dest_bci); break;
}
case Bytecodes::_tableswitch :
{
cur_block->set_control_bci(bci);
Bytecode_tableswitch sw(&s); int len = sw.length();
ciBlock *dest; int dest_bci; for (int i = 0; i < len; i++) {
dest_bci = s.cur_bci() + sw.dest_offset_at(i);
dest = make_block_at(dest_bci);
}
dest_bci = s.cur_bci() + sw.default_offset();
make_block_at(dest_bci); if (s.next_bci() < limit_bci) {
dest = make_block_at(s.next_bci());
}
} break;
case Bytecodes::_lookupswitch:
{
cur_block->set_control_bci(bci);
Bytecode_lookupswitch sw(&s); int len = sw.number_of_pairs();
ciBlock *dest; int dest_bci; for (int i = 0; i < len; i++) {
dest_bci = s.cur_bci() + sw.pair_at(i).offset();
dest = make_block_at(dest_bci);
}
dest_bci = s.cur_bci() + sw.default_offset();
dest = make_block_at(dest_bci); if (s.next_bci() < limit_bci) {
dest = make_block_at(s.next_bci());
}
} break;
case Bytecodes::_goto_w :
{
cur_block->set_control_bci(bci); if (s.next_bci() < limit_bci) {
(void) make_block_at(s.next_bci());
} int dest_bci = s.get_far_dest();
ciBlock *dest = make_block_at(dest_bci); break;
}
case Bytecodes::_jsr_w :
{
cur_block->set_control_bci(bci); if (s.next_bci() < limit_bci) {
ciBlock *ret = make_block_at(s.next_bci());
} int dest_bci = s.get_far_dest();
ciBlock *dest = make_block_at(dest_bci); break;
}
case Bytecodes::_athrow :
cur_block->set_may_throw(); // fall-through case Bytecodes::_ret : case Bytecodes::_ireturn : case Bytecodes::_lreturn : case Bytecodes::_freturn : case Bytecodes::_dreturn : case Bytecodes::_areturn : case Bytecodes::_return :
cur_block->set_control_bci(bci); if (s.next_bci() < limit_bci) {
(void) make_block_at(s.next_bci());
} break;
default: break;
}
} // End the last block
cur_block->set_limit_bci(limit_bci);
}
// create blocks for exception handlers if (meth->has_exception_handlers()) { for(ciExceptionHandlerStream str(meth); !str.is_done(); str.next()) {
ciExceptionHandler* handler = str.handler();
ciBlock *eb = make_block_at(handler->handler_bci()); // // Several exception handlers can have the same handler_bci: // // try { // if (a.foo(b) < 0) { // return a.error(); // } // return CoderResult.UNDERFLOW; // } finally { // a.position(b); // } // // The try block above is divided into 2 exception blocks // separated by 'areturn' bci. // int ex_start = handler->start(); int ex_end = handler->limit(); // ensure a block at the start of exception range and start of following code
(void) make_block_at(ex_start); if (ex_end < _code_size)
(void) make_block_at(ex_end);
if (eb->is_handler()) { // Extend old handler exception range to cover additional range. int old_ex_start = eb->ex_start_bci(); int old_ex_end = eb->ex_limit_bci(); if (ex_start > old_ex_start)
ex_start = old_ex_start; if (ex_end < old_ex_end)
ex_end = old_ex_end;
eb->clear_exception_handler(); // Reset exception information
}
eb->set_exception_range(ex_start, ex_end);
}
}
// scan the bytecodes and identify blocks
do_analysis();
// mark blocks that have exception handlers if (meth->has_exception_handlers()) { for(ciExceptionHandlerStream str(meth); !str.is_done(); str.next()) {
ciExceptionHandler* handler = str.handler(); int ex_start = handler->start(); int ex_end = handler->limit();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.