Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/ci/ciMethodBlocks.cpp
32285 views
/*1* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "ci/ciMethodBlocks.hpp"26#include "ci/ciStreams.hpp"27#include "interpreter/bytecode.hpp"28#include "utilities/copy.hpp"2930// ciMethodBlocks31323334ciBlock *ciMethodBlocks::block_containing(int bci) {35ciBlock *blk = _bci_to_block[bci];36return blk;37}3839bool ciMethodBlocks::is_block_start(int bci) {40assert(bci >=0 && bci < _code_size, "valid bytecode range");41ciBlock *b = _bci_to_block[bci];42assert(b != NULL, "must have block for bytecode");43return b->start_bci() == bci;44}4546// ------------------------------------------------------------------47// ciMethodBlocks::split_block_at48//49// Split the block spanning bci into two separate ranges. The former50// block becomes the second half and a new range is created for the51// first half. Returns the range beginning at bci.52ciBlock *ciMethodBlocks::split_block_at(int bci) {53ciBlock *former_block = block_containing(bci);54ciBlock *new_block = new(_arena) ciBlock(_method, _num_blocks++, former_block->start_bci());55_blocks->append(new_block);56assert(former_block != NULL, "must not be NULL");57new_block->set_limit_bci(bci);58former_block->set_start_bci(bci);59for (int pos=bci-1; pos >= 0; pos--) {60ciBlock *current_block = block_containing(pos);61if (current_block == former_block) {62// Replace it.63_bci_to_block[pos] = new_block;64} else if (current_block == NULL) {65// Non-bytecode start. Skip.66continue;67} else {68// We are done with our backwards walk69break;70}71}72// Move an exception handler information if needed.73if (former_block->is_handler()) {74int ex_start = former_block->ex_start_bci();75int ex_end = former_block->ex_limit_bci();76new_block->set_exception_range(ex_start, ex_end);77// Clear information in former_block.78former_block->clear_exception_handler();79}80return former_block;81}8283ciBlock *ciMethodBlocks::make_block_at(int bci) {84ciBlock *cb = block_containing(bci);85if (cb == NULL ) {86// This is our first time visiting this bytecode. Create87// a fresh block and assign it this starting point.88ciBlock *nb = new(_arena) ciBlock(_method, _num_blocks++, bci);89_blocks->append(nb);90_bci_to_block[bci] = nb;91return nb;92} else if (cb->start_bci() == bci) {93// The block begins at bci. Simply return it.94return cb;95} else {96// We have already created a block containing bci but97// not starting at bci. This existing block needs to98// be split into two.99return split_block_at(bci);100}101}102103ciBlock *ciMethodBlocks::make_dummy_block() {104ciBlock *dum = new(_arena) ciBlock(_method, -1, 0);105return dum;106}107108void ciMethodBlocks::do_analysis() {109ciBytecodeStream s(_method);110ciBlock *cur_block = block_containing(0);111int limit_bci = _method->code_size();112113while (s.next() != ciBytecodeStream::EOBC()) {114int bci = s.cur_bci();115// Determine if a new block has been made at the current bci. If116// this block differs from our current range, switch to the new117// one and end the old one.118assert(cur_block != NULL, "must always have a current block");119ciBlock *new_block = block_containing(bci);120if (new_block == NULL || new_block == cur_block) {121// We have not marked this bci as the start of a new block.122// Keep interpreting the current_range.123_bci_to_block[bci] = cur_block;124} else {125cur_block->set_limit_bci(bci);126cur_block = new_block;127}128129switch (s.cur_bc()) {130case Bytecodes::_ifeq :131case Bytecodes::_ifne :132case Bytecodes::_iflt :133case Bytecodes::_ifge :134case Bytecodes::_ifgt :135case Bytecodes::_ifle :136case Bytecodes::_if_icmpeq :137case Bytecodes::_if_icmpne :138case Bytecodes::_if_icmplt :139case Bytecodes::_if_icmpge :140case Bytecodes::_if_icmpgt :141case Bytecodes::_if_icmple :142case Bytecodes::_if_acmpeq :143case Bytecodes::_if_acmpne :144case Bytecodes::_ifnull :145case Bytecodes::_ifnonnull :146{147cur_block->set_control_bci(bci);148ciBlock *fall_through = make_block_at(s.next_bci());149int dest_bci = s.get_dest();150ciBlock *dest = make_block_at(dest_bci);151break;152}153154case Bytecodes::_goto :155{156cur_block->set_control_bci(bci);157if (s.next_bci() < limit_bci) {158(void) make_block_at(s.next_bci());159}160int dest_bci = s.get_dest();161ciBlock *dest = make_block_at(dest_bci);162break;163}164165case Bytecodes::_jsr :166{167cur_block->set_control_bci(bci);168ciBlock *ret = make_block_at(s.next_bci());169int dest_bci = s.get_dest();170ciBlock *dest = make_block_at(dest_bci);171break;172}173174case Bytecodes::_tableswitch :175{176cur_block->set_control_bci(bci);177Bytecode_tableswitch sw(&s);178int len = sw.length();179ciBlock *dest;180int dest_bci;181for (int i = 0; i < len; i++) {182dest_bci = s.cur_bci() + sw.dest_offset_at(i);183dest = make_block_at(dest_bci);184}185dest_bci = s.cur_bci() + sw.default_offset();186make_block_at(dest_bci);187if (s.next_bci() < limit_bci) {188dest = make_block_at(s.next_bci());189}190}191break;192193case Bytecodes::_lookupswitch:194{195cur_block->set_control_bci(bci);196Bytecode_lookupswitch sw(&s);197int len = sw.number_of_pairs();198ciBlock *dest;199int dest_bci;200for (int i = 0; i < len; i++) {201dest_bci = s.cur_bci() + sw.pair_at(i).offset();202dest = make_block_at(dest_bci);203}204dest_bci = s.cur_bci() + sw.default_offset();205dest = make_block_at(dest_bci);206if (s.next_bci() < limit_bci) {207dest = make_block_at(s.next_bci());208}209}210break;211212case Bytecodes::_goto_w :213{214cur_block->set_control_bci(bci);215if (s.next_bci() < limit_bci) {216(void) make_block_at(s.next_bci());217}218int dest_bci = s.get_far_dest();219ciBlock *dest = make_block_at(dest_bci);220break;221}222223case Bytecodes::_jsr_w :224{225cur_block->set_control_bci(bci);226ciBlock *ret = make_block_at(s.next_bci());227int dest_bci = s.get_far_dest();228ciBlock *dest = make_block_at(dest_bci);229break;230}231232case Bytecodes::_athrow :233cur_block->set_may_throw();234// fall-through235case Bytecodes::_ret :236case Bytecodes::_ireturn :237case Bytecodes::_lreturn :238case Bytecodes::_freturn :239case Bytecodes::_dreturn :240case Bytecodes::_areturn :241case Bytecodes::_return :242cur_block->set_control_bci(bci);243if (s.next_bci() < limit_bci) {244(void) make_block_at(s.next_bci());245}246break;247}248}249// End the last block250cur_block->set_limit_bci(limit_bci);251}252253ciMethodBlocks::ciMethodBlocks(Arena *arena, ciMethod *meth): _method(meth),254_arena(arena), _num_blocks(0), _code_size(meth->code_size()) {255int block_estimate = _code_size / 8;256257_blocks = new(_arena) GrowableArray<ciBlock *>(_arena, block_estimate, 0, NULL);258int b2bsize = _code_size * sizeof(ciBlock **);259_bci_to_block = (ciBlock **) arena->Amalloc(b2bsize);260Copy::zero_to_words((HeapWord*) _bci_to_block, b2bsize / sizeof(HeapWord));261262// create initial block covering the entire method263ciBlock *b = new(arena) ciBlock(_method, _num_blocks++, 0);264_blocks->append(b);265_bci_to_block[0] = b;266267// create blocks for exception handlers268if (meth->has_exception_handlers()) {269for(ciExceptionHandlerStream str(meth); !str.is_done(); str.next()) {270ciExceptionHandler* handler = str.handler();271ciBlock *eb = make_block_at(handler->handler_bci());272//273// Several exception handlers can have the same handler_bci:274//275// try {276// if (a.foo(b) < 0) {277// return a.error();278// }279// return CoderResult.UNDERFLOW;280// } finally {281// a.position(b);282// }283//284// The try block above is divided into 2 exception blocks285// separated by 'areturn' bci.286//287int ex_start = handler->start();288int ex_end = handler->limit();289// ensure a block at the start of exception range and start of following code290(void) make_block_at(ex_start);291if (ex_end < _code_size)292(void) make_block_at(ex_end);293294if (eb->is_handler()) {295// Extend old handler exception range to cover additional range.296int old_ex_start = eb->ex_start_bci();297int old_ex_end = eb->ex_limit_bci();298if (ex_start > old_ex_start)299ex_start = old_ex_start;300if (ex_end < old_ex_end)301ex_end = old_ex_end;302eb->clear_exception_handler(); // Reset exception information303}304eb->set_exception_range(ex_start, ex_end);305}306}307308// scan the bytecodes and identify blocks309do_analysis();310311// mark blocks that have exception handlers312if (meth->has_exception_handlers()) {313for(ciExceptionHandlerStream str(meth); !str.is_done(); str.next()) {314ciExceptionHandler* handler = str.handler();315int ex_start = handler->start();316int ex_end = handler->limit();317318int bci = ex_start;319while (bci < ex_end) {320ciBlock *b = block_containing(bci);321b->set_has_handler();322bci = b->limit_bci();323}324}325}326}327328void ciMethodBlocks::clear_processed() {329for (int i = 0; i < _blocks->length(); i++)330_blocks->at(i)->clear_processed();331}332333#ifndef PRODUCT334void ciMethodBlocks::dump() {335tty->print("---- blocks for method: ");336_method->print();337tty->cr();338for (int i = 0; i < _blocks->length(); i++) {339tty->print(" B%d: ", i); _blocks->at(i)->dump();340}341}342#endif343344345ciBlock::ciBlock(ciMethod *method, int index, int start_bci) :346#ifndef PRODUCT347_method(method),348#endif349_idx(index), _flags(0), _start_bci(start_bci), _limit_bci(-1), _control_bci(fall_through_bci),350_ex_start_bci(-1), _ex_limit_bci(-1) {351}352353void ciBlock::set_exception_range(int start_bci, int limit_bci) {354assert(limit_bci >= start_bci, "valid range");355assert(!is_handler() && _ex_start_bci == -1 && _ex_limit_bci == -1, "must not be handler");356_ex_start_bci = start_bci;357_ex_limit_bci = limit_bci;358set_handler();359}360361#ifndef PRODUCT362static const char *flagnames[] = {363"Processed",364"Handler",365"MayThrow",366"Jsr",367"Ret",368"RetTarget",369"HasHandler",370};371372void ciBlock::dump() {373tty->print(" [%d .. %d), {", _start_bci, _limit_bci);374for (int i = 0; i < 8; i++) {375if ((_flags & (1 << i)) != 0) {376tty->print(" %s", flagnames[i]);377}378}379tty->print(" ]");380if (is_handler())381tty->print(" handles(%d..%d)", _ex_start_bci, _ex_limit_bci);382tty->cr();383}384385// ------------------------------------------------------------------386// ciBlock::print_on387void ciBlock::print_on(outputStream* st) const {388st->print_cr("--------------------------------------------------------");389st->print ("ciBlock [%d - %d) control : ", start_bci(), limit_bci());390if (control_bci() == fall_through_bci) {391st->print_cr("%d:fall through", limit_bci());392} else {393st->print_cr("%d:%s", control_bci(),394Bytecodes::name(method()->java_code_at_bci(control_bci())));395}396397if (Verbose || WizardMode) {398method()->print_codes_on(start_bci(), limit_bci(), st);399}400}401#endif402403404