Path: blob/master/src/hotspot/share/ci/ciMethodBlocks.cpp
64440 views
/*1* Copyright (c) 2006, 2022, 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) {35assert(bci >= 0 && bci < _code_size, "valid bytecode range");36ciBlock *blk = _bci_to_block[bci];37return blk;38}3940bool ciMethodBlocks::is_block_start(int bci) {41assert(bci >= 0 && bci < _code_size, "valid bytecode range");42ciBlock *b = _bci_to_block[bci];43assert(b != NULL, "must have block for bytecode");44return b->start_bci() == bci;45}4647// ------------------------------------------------------------------48// ciMethodBlocks::split_block_at49//50// Split the block spanning bci into two separate ranges. The former51// block becomes the second half and a new range is created for the52// first half. Returns the range beginning at bci.53ciBlock *ciMethodBlocks::split_block_at(int bci) {54ciBlock *former_block = block_containing(bci);55ciBlock *new_block = new(_arena) ciBlock(_method, _num_blocks++, former_block->start_bci());56_blocks->append(new_block);57assert(former_block != NULL, "must not be NULL");58new_block->set_limit_bci(bci);59former_block->set_start_bci(bci);60for (int pos=bci-1; pos >= 0; pos--) {61ciBlock *current_block = block_containing(pos);62if (current_block == former_block) {63// Replace it.64_bci_to_block[pos] = new_block;65} else if (current_block == NULL) {66// Non-bytecode start. Skip.67continue;68} else {69// We are done with our backwards walk70break;71}72}73// Move an exception handler information if needed.74if (former_block->is_handler()) {75int ex_start = former_block->ex_start_bci();76int ex_end = former_block->ex_limit_bci();77new_block->set_exception_range(ex_start, ex_end);78// Clear information in former_block.79former_block->clear_exception_handler();80}81return former_block;82}8384ciBlock *ciMethodBlocks::make_block_at(int bci) {85ciBlock *cb = block_containing(bci);86if (cb == NULL ) {87// This is our first time visiting this bytecode. Create88// a fresh block and assign it this starting point.89ciBlock *nb = new(_arena) ciBlock(_method, _num_blocks++, bci);90_blocks->append(nb);91_bci_to_block[bci] = nb;92return nb;93} else if (cb->start_bci() == bci) {94// The block begins at bci. Simply return it.95return cb;96} else {97// We have already created a block containing bci but98// not starting at bci. This existing block needs to99// be split into two.100return split_block_at(bci);101}102}103104ciBlock *ciMethodBlocks::make_dummy_block() {105ciBlock *dum = new(_arena) ciBlock(_method, -1, 0);106return dum;107}108109void ciMethodBlocks::do_analysis() {110ciBytecodeStream s(_method);111ciBlock *cur_block = block_containing(0);112int limit_bci = _method->code_size();113114while (s.next() != ciBytecodeStream::EOBC()) {115int bci = s.cur_bci();116// Determine if a new block has been made at the current bci. If117// this block differs from our current range, switch to the new118// one and end the old one.119assert(cur_block != NULL, "must always have a current block");120ciBlock *new_block = block_containing(bci);121if (new_block == NULL || new_block == cur_block) {122// We have not marked this bci as the start of a new block.123// Keep interpreting the current_range.124_bci_to_block[bci] = cur_block;125} else {126cur_block->set_limit_bci(bci);127cur_block = new_block;128}129130switch (s.cur_bc()) {131case Bytecodes::_ifeq :132case Bytecodes::_ifne :133case Bytecodes::_iflt :134case Bytecodes::_ifge :135case Bytecodes::_ifgt :136case Bytecodes::_ifle :137case Bytecodes::_if_icmpeq :138case Bytecodes::_if_icmpne :139case Bytecodes::_if_icmplt :140case Bytecodes::_if_icmpge :141case Bytecodes::_if_icmpgt :142case Bytecodes::_if_icmple :143case Bytecodes::_if_acmpeq :144case Bytecodes::_if_acmpne :145case Bytecodes::_ifnull :146case Bytecodes::_ifnonnull :147{148cur_block->set_control_bci(bci);149if (s.next_bci() < limit_bci) {150ciBlock *fall_through = make_block_at(s.next_bci());151}152int dest_bci = s.get_dest();153ciBlock *dest = make_block_at(dest_bci);154break;155}156157case Bytecodes::_goto :158{159cur_block->set_control_bci(bci);160if (s.next_bci() < limit_bci) {161(void) make_block_at(s.next_bci());162}163int dest_bci = s.get_dest();164ciBlock *dest = make_block_at(dest_bci);165break;166}167168case Bytecodes::_jsr :169{170cur_block->set_control_bci(bci);171if (s.next_bci() < limit_bci) {172ciBlock *ret = make_block_at(s.next_bci());173}174int dest_bci = s.get_dest();175ciBlock *dest = make_block_at(dest_bci);176break;177}178179case Bytecodes::_tableswitch :180{181cur_block->set_control_bci(bci);182Bytecode_tableswitch sw(&s);183int len = sw.length();184ciBlock *dest;185int dest_bci;186for (int i = 0; i < len; i++) {187dest_bci = s.cur_bci() + sw.dest_offset_at(i);188dest = make_block_at(dest_bci);189}190dest_bci = s.cur_bci() + sw.default_offset();191make_block_at(dest_bci);192if (s.next_bci() < limit_bci) {193dest = make_block_at(s.next_bci());194}195}196break;197198case Bytecodes::_lookupswitch:199{200cur_block->set_control_bci(bci);201Bytecode_lookupswitch sw(&s);202int len = sw.number_of_pairs();203ciBlock *dest;204int dest_bci;205for (int i = 0; i < len; i++) {206dest_bci = s.cur_bci() + sw.pair_at(i).offset();207dest = make_block_at(dest_bci);208}209dest_bci = s.cur_bci() + sw.default_offset();210dest = make_block_at(dest_bci);211if (s.next_bci() < limit_bci) {212dest = make_block_at(s.next_bci());213}214}215break;216217case Bytecodes::_goto_w :218{219cur_block->set_control_bci(bci);220if (s.next_bci() < limit_bci) {221(void) make_block_at(s.next_bci());222}223int dest_bci = s.get_far_dest();224ciBlock *dest = make_block_at(dest_bci);225break;226}227228case Bytecodes::_jsr_w :229{230cur_block->set_control_bci(bci);231if (s.next_bci() < limit_bci) {232ciBlock *ret = make_block_at(s.next_bci());233}234int dest_bci = s.get_far_dest();235ciBlock *dest = make_block_at(dest_bci);236break;237}238239case Bytecodes::_athrow :240cur_block->set_may_throw();241// fall-through242case Bytecodes::_ret :243case Bytecodes::_ireturn :244case Bytecodes::_lreturn :245case Bytecodes::_freturn :246case Bytecodes::_dreturn :247case Bytecodes::_areturn :248case Bytecodes::_return :249cur_block->set_control_bci(bci);250if (s.next_bci() < limit_bci) {251(void) make_block_at(s.next_bci());252}253break;254255default:256break;257}258}259// End the last block260cur_block->set_limit_bci(limit_bci);261}262263ciMethodBlocks::ciMethodBlocks(Arena *arena, ciMethod *meth): _method(meth),264_arena(arena), _num_blocks(0), _code_size(meth->code_size()) {265int block_estimate = _code_size / 8;266267_blocks = new(_arena) GrowableArray<ciBlock *>(_arena, block_estimate, 0, NULL);268int b2bsize = _code_size * sizeof(ciBlock **);269_bci_to_block = (ciBlock **) arena->Amalloc(b2bsize);270Copy::zero_to_words((HeapWord*) _bci_to_block, b2bsize / sizeof(HeapWord));271272// create initial block covering the entire method273ciBlock *b = new(arena) ciBlock(_method, _num_blocks++, 0);274_blocks->append(b);275_bci_to_block[0] = b;276277// create blocks for exception handlers278if (meth->has_exception_handlers()) {279for(ciExceptionHandlerStream str(meth); !str.is_done(); str.next()) {280ciExceptionHandler* handler = str.handler();281ciBlock *eb = make_block_at(handler->handler_bci());282//283// Several exception handlers can have the same handler_bci:284//285// try {286// if (a.foo(b) < 0) {287// return a.error();288// }289// return CoderResult.UNDERFLOW;290// } finally {291// a.position(b);292// }293//294// The try block above is divided into 2 exception blocks295// separated by 'areturn' bci.296//297int ex_start = handler->start();298int ex_end = handler->limit();299// ensure a block at the start of exception range and start of following code300(void) make_block_at(ex_start);301if (ex_end < _code_size)302(void) make_block_at(ex_end);303304if (eb->is_handler()) {305// Extend old handler exception range to cover additional range.306int old_ex_start = eb->ex_start_bci();307int old_ex_end = eb->ex_limit_bci();308if (ex_start > old_ex_start)309ex_start = old_ex_start;310if (ex_end < old_ex_end)311ex_end = old_ex_end;312eb->clear_exception_handler(); // Reset exception information313}314eb->set_exception_range(ex_start, ex_end);315}316}317318// scan the bytecodes and identify blocks319do_analysis();320321// mark blocks that have exception handlers322if (meth->has_exception_handlers()) {323for(ciExceptionHandlerStream str(meth); !str.is_done(); str.next()) {324ciExceptionHandler* handler = str.handler();325int ex_start = handler->start();326int ex_end = handler->limit();327328int bci = ex_start;329while (bci < ex_end) {330ciBlock *b = block_containing(bci);331b->set_has_handler();332bci = b->limit_bci();333}334}335}336}337338void ciMethodBlocks::clear_processed() {339for (int i = 0; i < _blocks->length(); i++)340_blocks->at(i)->clear_processed();341}342343#ifndef PRODUCT344void ciMethodBlocks::dump() {345tty->print("---- blocks for method: ");346_method->print();347tty->cr();348for (int i = 0; i < _blocks->length(); i++) {349tty->print(" B%d: ", i); _blocks->at(i)->dump();350}351}352#endif353354ciBlock::ciBlock(ciMethod *method, int index, int start_bci) :355_idx(index), _start_bci(start_bci), _limit_bci(-1), _control_bci(fall_through_bci),356_flags(0), _ex_start_bci(-1), _ex_limit_bci(-1)357#ifndef PRODUCT358, _method(method)359#endif360{361}362363void ciBlock::set_exception_range(int start_bci, int limit_bci) {364assert(limit_bci >= start_bci, "valid range");365assert(!is_handler() && _ex_start_bci == -1 && _ex_limit_bci == -1, "must not be handler");366_ex_start_bci = start_bci;367_ex_limit_bci = limit_bci;368set_handler();369}370371#ifndef PRODUCT372static const char *flagnames[] = {373"Processed",374"Handler",375"MayThrow",376"Jsr",377"Ret",378"RetTarget",379"HasHandler",380};381382void ciBlock::dump() {383tty->print(" [%d .. %d), {", _start_bci, _limit_bci);384for (int i = 0; i < 7; i++) {385if ((_flags & (1 << i)) != 0) {386tty->print(" %s", flagnames[i]);387}388}389tty->print(" ]");390if (is_handler())391tty->print(" handles(%d..%d)", _ex_start_bci, _ex_limit_bci);392tty->cr();393}394395// ------------------------------------------------------------------396// ciBlock::print_on397void ciBlock::print_on(outputStream* st) const {398st->print_cr("--------------------------------------------------------");399st->print ("ciBlock [%d - %d) control : ", start_bci(), limit_bci());400if (control_bci() == fall_through_bci) {401st->print_cr("%d:fall through", limit_bci());402} else {403st->print_cr("%d:%s", control_bci(),404Bytecodes::name(method()->java_code_at_bci(control_bci())));405}406407if (Verbose || WizardMode) {408method()->print_codes_on(start_bci(), limit_bci(), st);409}410}411#endif412413414