duke@435: /* duke@435: * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: // The MethodLiveness class performs a simple liveness analysis on a method duke@435: // in order to decide which locals are live (that is, will be used again) at duke@435: // a particular bytecode index (bci). duke@435: // duke@435: // The algorithm goes: duke@435: // duke@435: // 1. Break the method into a set of basic blocks. For each basic block we duke@435: // also keep track of its set of predecessors through normal control flow duke@435: // and predecessors through exceptional control flow. duke@435: // duke@435: // 2. For each basic block, compute two sets, gen (the set of values used before duke@435: // they are defined) and kill (the set of values defined before they are used) duke@435: // in the basic block. A basic block "needs" the locals in its gen set to duke@435: // perform its computation. A basic block "provides" values for the locals in duke@435: // its kill set, allowing a need from a successor to be ignored. duke@435: // duke@435: // 3. Liveness information (the set of locals which are needed) is pushed backwards through duke@435: // the program, from blocks to their predecessors. We compute and store liveness duke@435: // information for the normal/exceptional exit paths for each basic block. When duke@435: // this process reaches a fixed point, we are done. duke@435: // duke@435: // 4. When we are asked about the liveness at a particular bci with a basic block, we duke@435: // compute gen/kill sets which represent execution from that bci to the exit of duke@435: // its blocks. We then compose this range gen/kill information with the normal duke@435: // and exceptional exit information for the block to produce liveness information duke@435: // at that bci. duke@435: // duke@435: // The algorithm is approximate in many respects. Notably: duke@435: // duke@435: // 1. We do not do the analysis necessary to match jsr's with the appropriate ret. duke@435: // Instead we make the conservative assumption that any ret can return to any duke@435: // jsr return site. duke@435: // 2. Instead of computing the effects of exceptions at every instruction, we duke@435: // summarize the effects of all exceptional continuations from the block as duke@435: // a single set (_exception_exit), losing some information but simplifying the duke@435: // analysis. duke@435: duke@435: duke@435: # include "incls/_precompiled.incl" duke@435: # include "incls/_methodLiveness.cpp.incl" duke@435: duke@435: //-------------------------------------------------------------------------- duke@435: // The BitCounter class is used for counting the number of bits set in duke@435: // some BitMap. It is only used when collecting liveness statistics. duke@435: duke@435: #ifndef PRODUCT duke@435: duke@435: class BitCounter: public BitMapClosure { duke@435: private: duke@435: int _count; duke@435: public: duke@435: BitCounter() : _count(0) {} duke@435: duke@435: // Callback when bit in map is set duke@435: virtual void do_bit(size_t offset) { duke@435: _count++; duke@435: } duke@435: duke@435: int count() { duke@435: return _count; duke@435: } duke@435: }; duke@435: duke@435: duke@435: //-------------------------------------------------------------------------- duke@435: duke@435: duke@435: // Counts duke@435: long MethodLiveness::_total_bytes = 0; duke@435: int MethodLiveness::_total_methods = 0; duke@435: duke@435: long MethodLiveness::_total_blocks = 0; duke@435: int MethodLiveness::_max_method_blocks = 0; duke@435: duke@435: long MethodLiveness::_total_edges = 0; duke@435: int MethodLiveness::_max_block_edges = 0; duke@435: duke@435: long MethodLiveness::_total_exc_edges = 0; duke@435: int MethodLiveness::_max_block_exc_edges = 0; duke@435: duke@435: long MethodLiveness::_total_method_locals = 0; duke@435: int MethodLiveness::_max_method_locals = 0; duke@435: duke@435: long MethodLiveness::_total_locals_queried = 0; duke@435: long MethodLiveness::_total_live_locals_queried = 0; duke@435: duke@435: long MethodLiveness::_total_visits = 0; duke@435: duke@435: #endif duke@435: duke@435: // Timers duke@435: elapsedTimer MethodLiveness::_time_build_graph; duke@435: elapsedTimer MethodLiveness::_time_gen_kill; duke@435: elapsedTimer MethodLiveness::_time_flow; duke@435: elapsedTimer MethodLiveness::_time_query; duke@435: elapsedTimer MethodLiveness::_time_total; duke@435: duke@435: MethodLiveness::MethodLiveness(Arena* arena, ciMethod* method) duke@435: #ifdef COMPILER1 duke@435: : _bci_block_start((uintptr_t*)arena->Amalloc((method->code_size() >> LogBitsPerByte) + 1), method->code_size()) duke@435: #endif duke@435: { duke@435: _arena = arena; duke@435: _method = method; duke@435: _bit_map_size_bits = method->max_locals(); duke@435: _bit_map_size_words = (_bit_map_size_bits / sizeof(unsigned int)) + 1; duke@435: duke@435: #ifdef COMPILER1 duke@435: _bci_block_start.clear(); duke@435: #endif duke@435: } duke@435: duke@435: void MethodLiveness::compute_liveness() { duke@435: #ifndef PRODUCT duke@435: if (TraceLivenessGen) { duke@435: tty->print_cr("################################################################"); duke@435: tty->print("# Computing liveness information for "); duke@435: method()->print_short_name(); duke@435: } duke@435: duke@435: if (TimeLivenessAnalysis) _time_total.start(); duke@435: #endif duke@435: duke@435: { duke@435: TraceTime buildGraph(NULL, &_time_build_graph, TimeLivenessAnalysis); duke@435: init_basic_blocks(); duke@435: } duke@435: { duke@435: TraceTime genKill(NULL, &_time_gen_kill, TimeLivenessAnalysis); duke@435: init_gen_kill(); duke@435: } duke@435: { duke@435: TraceTime flow(NULL, &_time_flow, TimeLivenessAnalysis); duke@435: propagate_liveness(); duke@435: } duke@435: duke@435: #ifndef PRODUCT duke@435: if (TimeLivenessAnalysis) _time_total.stop(); duke@435: duke@435: if (TimeLivenessAnalysis) { duke@435: // Collect statistics duke@435: _total_bytes += method()->code_size(); duke@435: _total_methods++; duke@435: duke@435: int num_blocks = _block_count; duke@435: _total_blocks += num_blocks; duke@435: _max_method_blocks = MAX2(num_blocks,_max_method_blocks); duke@435: duke@435: for (int i=0; i_normal_predecessors->length(); duke@435: int numExcEdges = block->_exception_predecessors->length(); duke@435: duke@435: _total_edges += numEdges; duke@435: _total_exc_edges += numExcEdges; duke@435: _max_block_edges = MAX2(numEdges,_max_block_edges); duke@435: _max_block_exc_edges = MAX2(numExcEdges,_max_block_exc_edges); duke@435: } duke@435: duke@435: int numLocals = _bit_map_size_bits; duke@435: _total_method_locals += numLocals; duke@435: _max_method_locals = MAX2(numLocals,_max_method_locals); duke@435: } duke@435: #endif duke@435: } duke@435: duke@435: duke@435: void MethodLiveness::init_basic_blocks() { duke@435: bool bailout = false; duke@435: duke@435: int method_len = method()->code_size(); duke@435: ciMethodBlocks *mblocks = method()->get_method_blocks(); duke@435: duke@435: // Create an array to store the bci->BasicBlock mapping. duke@435: _block_map = new (arena()) GrowableArray(arena(), method_len, method_len, NULL); duke@435: duke@435: _block_count = mblocks->num_blocks(); duke@435: _block_list = (BasicBlock **) arena()->Amalloc(sizeof(BasicBlock *) * _block_count); duke@435: duke@435: // Used for patching up jsr/ret control flow. duke@435: GrowableArray* jsr_exit_list = new GrowableArray(5); duke@435: GrowableArray* ret_list = new GrowableArray(5); duke@435: duke@435: // generate our block list from ciMethodBlocks duke@435: for (int blk = 0; blk < _block_count; blk++) { duke@435: ciBlock *cib = mblocks->block(blk); duke@435: int start_bci = cib->start_bci(); duke@435: _block_list[blk] = new (arena()) BasicBlock(this, start_bci, cib->limit_bci()); duke@435: _block_map->at_put(start_bci, _block_list[blk]); duke@435: #ifdef COMPILER1 duke@435: // mark all bcis where a new basic block starts duke@435: _bci_block_start.set_bit(start_bci); duke@435: #endif // COMPILER1 duke@435: } duke@435: // fill in the predecessors of blocks duke@435: ciBytecodeStream bytes(method()); duke@435: duke@435: for (int blk = 0; blk < _block_count; blk++) { duke@435: BasicBlock *current_block = _block_list[blk]; duke@435: int bci = mblocks->block(blk)->control_bci(); duke@435: duke@435: if (bci == ciBlock::fall_through_bci) { duke@435: int limit = current_block->limit_bci(); duke@435: if (limit < method_len) { duke@435: BasicBlock *next = _block_map->at(limit); duke@435: assert( next != NULL, "must be a block immediately following this one."); duke@435: next->add_normal_predecessor(current_block); duke@435: } duke@435: continue; duke@435: } duke@435: bytes.reset_to_bci(bci); duke@435: Bytecodes::Code code = bytes.next(); duke@435: BasicBlock *dest; duke@435: duke@435: // Now we need to interpret the instruction's effect duke@435: // on control flow. duke@435: assert (current_block != NULL, "we must have a current block"); duke@435: switch (code) { duke@435: case Bytecodes::_ifeq: duke@435: case Bytecodes::_ifne: duke@435: case Bytecodes::_iflt: duke@435: case Bytecodes::_ifge: duke@435: case Bytecodes::_ifgt: duke@435: case Bytecodes::_ifle: duke@435: case Bytecodes::_if_icmpeq: duke@435: case Bytecodes::_if_icmpne: duke@435: case Bytecodes::_if_icmplt: duke@435: case Bytecodes::_if_icmpge: duke@435: case Bytecodes::_if_icmpgt: duke@435: case Bytecodes::_if_icmple: duke@435: case Bytecodes::_if_acmpeq: duke@435: case Bytecodes::_if_acmpne: duke@435: case Bytecodes::_ifnull: duke@435: case Bytecodes::_ifnonnull: duke@435: // Two way branch. Set predecessors at each destination. duke@435: dest = _block_map->at(bytes.next_bci()); duke@435: assert(dest != NULL, "must be a block immediately following this one."); duke@435: dest->add_normal_predecessor(current_block); duke@435: duke@435: dest = _block_map->at(bytes.get_dest()); duke@435: assert(dest != NULL, "branch desination must start a block."); duke@435: dest->add_normal_predecessor(current_block); duke@435: break; duke@435: case Bytecodes::_goto: duke@435: dest = _block_map->at(bytes.get_dest()); duke@435: assert(dest != NULL, "branch desination must start a block."); duke@435: dest->add_normal_predecessor(current_block); duke@435: break; duke@435: case Bytecodes::_goto_w: duke@435: dest = _block_map->at(bytes.get_far_dest()); duke@435: assert(dest != NULL, "branch desination must start a block."); duke@435: dest->add_normal_predecessor(current_block); duke@435: break; duke@435: case Bytecodes::_tableswitch: duke@435: { duke@435: Bytecode_tableswitch *tableswitch = duke@435: Bytecode_tableswitch_at(bytes.cur_bcp()); duke@435: duke@435: int len = tableswitch->length(); duke@435: duke@435: dest = _block_map->at(bci + tableswitch->default_offset()); duke@435: assert(dest != NULL, "branch desination must start a block."); duke@435: dest->add_normal_predecessor(current_block); duke@435: while (--len >= 0) { duke@435: dest = _block_map->at(bci + tableswitch->dest_offset_at(len)); duke@435: assert(dest != NULL, "branch desination must start a block."); duke@435: dest->add_normal_predecessor(current_block); duke@435: } duke@435: break; duke@435: } duke@435: duke@435: case Bytecodes::_lookupswitch: duke@435: { duke@435: Bytecode_lookupswitch *lookupswitch = duke@435: Bytecode_lookupswitch_at(bytes.cur_bcp()); duke@435: duke@435: int npairs = lookupswitch->number_of_pairs(); duke@435: duke@435: dest = _block_map->at(bci + lookupswitch->default_offset()); duke@435: assert(dest != NULL, "branch desination must start a block."); duke@435: dest->add_normal_predecessor(current_block); duke@435: while(--npairs >= 0) { duke@435: LookupswitchPair *pair = lookupswitch->pair_at(npairs); duke@435: dest = _block_map->at( bci + pair->offset()); duke@435: assert(dest != NULL, "branch desination must start a block."); duke@435: dest->add_normal_predecessor(current_block); duke@435: } duke@435: break; duke@435: } duke@435: duke@435: case Bytecodes::_jsr: duke@435: { duke@435: assert(bytes.is_wide()==false, "sanity check"); duke@435: dest = _block_map->at(bytes.get_dest()); duke@435: assert(dest != NULL, "branch desination must start a block."); duke@435: dest->add_normal_predecessor(current_block); duke@435: BasicBlock *jsrExit = _block_map->at(current_block->limit_bci()); duke@435: assert(jsrExit != NULL, "jsr return bci must start a block."); duke@435: jsr_exit_list->append(jsrExit); duke@435: break; duke@435: } duke@435: case Bytecodes::_jsr_w: duke@435: { duke@435: dest = _block_map->at(bytes.get_far_dest()); duke@435: assert(dest != NULL, "branch desination must start a block."); duke@435: dest->add_normal_predecessor(current_block); duke@435: BasicBlock *jsrExit = _block_map->at(current_block->limit_bci()); duke@435: assert(jsrExit != NULL, "jsr return bci must start a block."); duke@435: jsr_exit_list->append(jsrExit); duke@435: break; duke@435: } duke@435: duke@435: case Bytecodes::_wide: duke@435: assert(false, "wide opcodes should not be seen here"); duke@435: break; duke@435: case Bytecodes::_athrow: duke@435: case Bytecodes::_ireturn: duke@435: case Bytecodes::_lreturn: duke@435: case Bytecodes::_freturn: duke@435: case Bytecodes::_dreturn: duke@435: case Bytecodes::_areturn: duke@435: case Bytecodes::_return: duke@435: // These opcodes are not the normal predecessors of any other opcodes. duke@435: break; duke@435: case Bytecodes::_ret: duke@435: // We will patch up jsr/rets in a subsequent pass. duke@435: ret_list->append(current_block); duke@435: break; duke@435: case Bytecodes::_breakpoint: duke@435: // Bail out of there are breakpoints in here. duke@435: bailout = true; duke@435: break; duke@435: default: duke@435: // Do nothing. duke@435: break; duke@435: } duke@435: } duke@435: // Patch up the jsr/ret's. We conservatively assume that any ret duke@435: // can return to any jsr site. duke@435: int ret_list_len = ret_list->length(); duke@435: int jsr_exit_list_len = jsr_exit_list->length(); duke@435: if (ret_list_len > 0 && jsr_exit_list_len > 0) { duke@435: for (int i = jsr_exit_list_len - 1; i >= 0; i--) { duke@435: BasicBlock *jsrExit = jsr_exit_list->at(i); duke@435: for (int i = ret_list_len - 1; i >= 0; i--) { duke@435: jsrExit->add_normal_predecessor(ret_list->at(i)); duke@435: } duke@435: } duke@435: } duke@435: duke@435: // Compute exception edges. duke@435: for (int b=_block_count-1; b >= 0; b--) { duke@435: BasicBlock *block = _block_list[b]; duke@435: int block_start = block->start_bci(); duke@435: int block_limit = block->limit_bci(); duke@435: ciExceptionHandlerStream handlers(method()); duke@435: for (; !handlers.is_done(); handlers.next()) { duke@435: ciExceptionHandler* handler = handlers.handler(); duke@435: int start = handler->start(); duke@435: int limit = handler->limit(); duke@435: int handler_bci = handler->handler_bci(); duke@435: duke@435: int intersect_start = MAX2(block_start, start); duke@435: int intersect_limit = MIN2(block_limit, limit); duke@435: if (intersect_start < intersect_limit) { duke@435: // The catch range has a nonempty intersection with this duke@435: // basic block. That means this basic block can be an duke@435: // exceptional predecessor. duke@435: _block_map->at(handler_bci)->add_exception_predecessor(block); duke@435: duke@435: if (handler->is_catch_all()) { duke@435: // This is a catch-all block. duke@435: if (intersect_start == block_start && intersect_limit == block_limit) { duke@435: // The basic block is entirely contained in this catch-all block. duke@435: // Skip the rest of the exception handlers -- they can never be duke@435: // reached in execution. duke@435: break; duke@435: } duke@435: } duke@435: } duke@435: } duke@435: } duke@435: } duke@435: duke@435: void MethodLiveness::init_gen_kill() { duke@435: for (int i=_block_count-1; i >= 0; i--) { duke@435: _block_list[i]->compute_gen_kill(method()); duke@435: } duke@435: } duke@435: duke@435: void MethodLiveness::propagate_liveness() { duke@435: int num_blocks = _block_count; duke@435: BasicBlock *block; duke@435: duke@435: // We start our work list off with all blocks in it. duke@435: // Alternately, we could start off the work list with the list of all duke@435: // blocks which could exit the method directly, along with one block duke@435: // from any infinite loop. If this matters, it can be changed. It duke@435: // may not be clear from looking at the code, but the order of the duke@435: // workList will be the opposite of the creation order of the basic duke@435: // blocks, which should be decent for quick convergence (with the duke@435: // possible exception of exception handlers, which are all created duke@435: // early). duke@435: _work_list = NULL; duke@435: for (int i = 0; i < num_blocks; i++) { duke@435: block = _block_list[i]; duke@435: block->set_next(_work_list); duke@435: block->set_on_work_list(true); duke@435: _work_list = block; duke@435: } duke@435: duke@435: duke@435: while ((block = work_list_get()) != NULL) { duke@435: block->propagate(this); duke@435: NOT_PRODUCT(_total_visits++;) duke@435: } duke@435: } duke@435: duke@435: void MethodLiveness::work_list_add(BasicBlock *block) { duke@435: if (!block->on_work_list()) { duke@435: block->set_next(_work_list); duke@435: block->set_on_work_list(true); duke@435: _work_list = block; duke@435: } duke@435: } duke@435: duke@435: MethodLiveness::BasicBlock *MethodLiveness::work_list_get() { duke@435: BasicBlock *block = _work_list; duke@435: if (block != NULL) { duke@435: block->set_on_work_list(false); duke@435: _work_list = block->next(); duke@435: } duke@435: return block; duke@435: } duke@435: duke@435: duke@435: MethodLivenessResult MethodLiveness::get_liveness_at(int entry_bci) { duke@435: int bci = entry_bci; duke@435: bool is_entry = false; duke@435: if (entry_bci == InvocationEntryBci) { duke@435: is_entry = true; duke@435: bci = 0; duke@435: } duke@435: duke@435: MethodLivenessResult answer(NULL,0); duke@435: duke@435: if (_block_count > 0) { duke@435: if (TimeLivenessAnalysis) _time_total.start(); duke@435: if (TimeLivenessAnalysis) _time_query.start(); duke@435: duke@435: assert( 0 <= bci && bci < method()->code_size(), "bci out of range" ); duke@435: BasicBlock *block = _block_map->at(bci); duke@435: // We may not be at the block start, so search backwards to find the block duke@435: // containing bci. duke@435: int t = bci; duke@435: while (block == NULL && t > 0) { duke@435: block = _block_map->at(--t); duke@435: } duke@435: assert( block != NULL, "invalid bytecode index; must be instruction index" ); duke@435: assert(bci >= block->start_bci() && bci < block->limit_bci(), "block must contain bci."); duke@435: duke@435: answer = block->get_liveness_at(method(), bci); duke@435: duke@435: if (is_entry && method()->is_synchronized() && !method()->is_static()) { duke@435: // Synchronized methods use the receiver once on entry. duke@435: answer.at_put(0, true); duke@435: } duke@435: duke@435: #ifndef PRODUCT duke@435: if (TraceLivenessQuery) { duke@435: tty->print("Liveness query of "); duke@435: method()->print_short_name(); duke@435: tty->print(" @ %d : result is ", bci); duke@435: answer.print_on(tty); duke@435: } duke@435: duke@435: if (TimeLivenessAnalysis) _time_query.stop(); duke@435: if (TimeLivenessAnalysis) _time_total.stop(); duke@435: #endif duke@435: } duke@435: duke@435: #ifndef PRODUCT duke@435: if (TimeLivenessAnalysis) { duke@435: // Collect statistics. duke@435: _total_locals_queried += _bit_map_size_bits; duke@435: BitCounter counter; duke@435: answer.iterate(&counter); duke@435: _total_live_locals_queried += counter.count(); duke@435: } duke@435: #endif duke@435: duke@435: return answer; duke@435: } duke@435: duke@435: duke@435: #ifndef PRODUCT duke@435: duke@435: void MethodLiveness::print_times() { duke@435: tty->print_cr ("Accumulated liveness analysis times/statistics:"); duke@435: tty->print_cr ("-----------------------------------------------"); duke@435: tty->print_cr (" Total : %3.3f sec.", _time_total.seconds()); duke@435: tty->print_cr (" Build graph : %3.3f sec. (%2.2f%%)", _time_build_graph.seconds(), duke@435: _time_build_graph.seconds() * 100 / _time_total.seconds()); duke@435: tty->print_cr (" Gen / Kill : %3.3f sec. (%2.2f%%)", _time_gen_kill.seconds(), duke@435: _time_gen_kill.seconds() * 100 / _time_total.seconds()); duke@435: tty->print_cr (" Dataflow : %3.3f sec. (%2.2f%%)", _time_flow.seconds(), duke@435: _time_flow.seconds() * 100 / _time_total.seconds()); duke@435: tty->print_cr (" Query : %3.3f sec. (%2.2f%%)", _time_query.seconds(), duke@435: _time_query.seconds() * 100 / _time_total.seconds()); duke@435: tty->print_cr (" #bytes : %8d (%3.0f bytes per sec)", duke@435: _total_bytes, duke@435: _total_bytes / _time_total.seconds()); duke@435: tty->print_cr (" #methods : %8d (%3.0f methods per sec)", duke@435: _total_methods, duke@435: _total_methods / _time_total.seconds()); duke@435: tty->print_cr (" avg locals : %3.3f max locals : %3d", duke@435: (float)_total_method_locals / _total_methods, duke@435: _max_method_locals); duke@435: tty->print_cr (" avg blocks : %3.3f max blocks : %3d", duke@435: (float)_total_blocks / _total_methods, duke@435: _max_method_blocks); duke@435: tty->print_cr (" avg bytes : %3.3f", duke@435: (float)_total_bytes / _total_methods); duke@435: tty->print_cr (" #blocks : %8d", duke@435: _total_blocks); duke@435: tty->print_cr (" avg normal predecessors : %3.3f max normal predecessors : %3d", duke@435: (float)_total_edges / _total_blocks, duke@435: _max_block_edges); duke@435: tty->print_cr (" avg exception predecessors : %3.3f max exception predecessors : %3d", duke@435: (float)_total_exc_edges / _total_blocks, duke@435: _max_block_exc_edges); duke@435: tty->print_cr (" avg visits : %3.3f", duke@435: (float)_total_visits / _total_blocks); duke@435: tty->print_cr (" #locals queried : %8d #live : %8d %%live : %2.2f%%", duke@435: _total_locals_queried, duke@435: _total_live_locals_queried, duke@435: 100.0 * _total_live_locals_queried / _total_locals_queried); duke@435: } duke@435: duke@435: #endif duke@435: duke@435: duke@435: MethodLiveness::BasicBlock::BasicBlock(MethodLiveness *analyzer, int start, int limit) : duke@435: _gen((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()), duke@435: analyzer->bit_map_size_bits()), duke@435: _kill((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()), duke@435: analyzer->bit_map_size_bits()), duke@435: _entry((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()), duke@435: analyzer->bit_map_size_bits()), duke@435: _normal_exit((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()), duke@435: analyzer->bit_map_size_bits()), duke@435: _exception_exit((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()), duke@435: analyzer->bit_map_size_bits()), duke@435: _last_bci(-1) { duke@435: _analyzer = analyzer; duke@435: _start_bci = start; duke@435: _limit_bci = limit; duke@435: _normal_predecessors = duke@435: new (analyzer->arena()) GrowableArray(analyzer->arena(), 5, 0, NULL); duke@435: _exception_predecessors = duke@435: new (analyzer->arena()) GrowableArray(analyzer->arena(), 5, 0, NULL); duke@435: _normal_exit.clear(); duke@435: _exception_exit.clear(); duke@435: _entry.clear(); duke@435: duke@435: // this initialization is not strictly necessary. duke@435: // _gen and _kill are cleared at the beginning of compute_gen_kill_range() duke@435: _gen.clear(); duke@435: _kill.clear(); duke@435: } duke@435: duke@435: duke@435: duke@435: MethodLiveness::BasicBlock *MethodLiveness::BasicBlock::split(int split_bci) { duke@435: int start = _start_bci; duke@435: int limit = _limit_bci; duke@435: duke@435: if (TraceLivenessGen) { duke@435: tty->print_cr(" ** Splitting block (%d,%d) at %d", start, limit, split_bci); duke@435: } duke@435: duke@435: GrowableArray* save_predecessors = _normal_predecessors; duke@435: duke@435: assert (start < split_bci && split_bci < limit, "improper split"); duke@435: duke@435: // Make a new block to cover the first half of the range. duke@435: BasicBlock *first_half = new (_analyzer->arena()) BasicBlock(_analyzer, start, split_bci); duke@435: duke@435: // Assign correct values to the second half (this) duke@435: _normal_predecessors = first_half->_normal_predecessors; duke@435: _start_bci = split_bci; duke@435: add_normal_predecessor(first_half); duke@435: duke@435: // Assign correct predecessors to the new first half duke@435: first_half->_normal_predecessors = save_predecessors; duke@435: duke@435: return first_half; duke@435: } duke@435: duke@435: void MethodLiveness::BasicBlock::compute_gen_kill(ciMethod* method) { duke@435: ciBytecodeStream bytes(method); duke@435: bytes.reset_to_bci(start_bci()); duke@435: bytes.set_max_bci(limit_bci()); duke@435: compute_gen_kill_range(&bytes); duke@435: duke@435: } duke@435: duke@435: void MethodLiveness::BasicBlock::compute_gen_kill_range(ciBytecodeStream *bytes) { duke@435: _gen.clear(); duke@435: _kill.clear(); duke@435: duke@435: while (bytes->next() != ciBytecodeStream::EOBC()) { duke@435: compute_gen_kill_single(bytes); duke@435: } duke@435: } duke@435: duke@435: void MethodLiveness::BasicBlock::compute_gen_kill_single(ciBytecodeStream *instruction) { duke@435: int localNum; duke@435: duke@435: // We prohibit _gen and _kill from having locals in common. If we duke@435: // know that one is definitely going to be applied before the other, duke@435: // we could save some computation time by relaxing this prohibition. duke@435: duke@435: switch (instruction->cur_bc()) { duke@435: case Bytecodes::_nop: duke@435: case Bytecodes::_goto: duke@435: case Bytecodes::_goto_w: duke@435: case Bytecodes::_aconst_null: duke@435: case Bytecodes::_new: duke@435: case Bytecodes::_iconst_m1: duke@435: case Bytecodes::_iconst_0: duke@435: case Bytecodes::_iconst_1: duke@435: case Bytecodes::_iconst_2: duke@435: case Bytecodes::_iconst_3: duke@435: case Bytecodes::_iconst_4: duke@435: case Bytecodes::_iconst_5: duke@435: case Bytecodes::_fconst_0: duke@435: case Bytecodes::_fconst_1: duke@435: case Bytecodes::_fconst_2: duke@435: case Bytecodes::_bipush: duke@435: case Bytecodes::_sipush: duke@435: case Bytecodes::_lconst_0: duke@435: case Bytecodes::_lconst_1: duke@435: case Bytecodes::_dconst_0: duke@435: case Bytecodes::_dconst_1: duke@435: case Bytecodes::_ldc2_w: duke@435: case Bytecodes::_ldc: duke@435: case Bytecodes::_ldc_w: duke@435: case Bytecodes::_iaload: duke@435: case Bytecodes::_faload: duke@435: case Bytecodes::_baload: duke@435: case Bytecodes::_caload: duke@435: case Bytecodes::_saload: duke@435: case Bytecodes::_laload: duke@435: case Bytecodes::_daload: duke@435: case Bytecodes::_aaload: duke@435: case Bytecodes::_iastore: duke@435: case Bytecodes::_fastore: duke@435: case Bytecodes::_bastore: duke@435: case Bytecodes::_castore: duke@435: case Bytecodes::_sastore: duke@435: case Bytecodes::_lastore: duke@435: case Bytecodes::_dastore: duke@435: case Bytecodes::_aastore: duke@435: case Bytecodes::_pop: duke@435: case Bytecodes::_pop2: duke@435: case Bytecodes::_dup: duke@435: case Bytecodes::_dup_x1: duke@435: case Bytecodes::_dup_x2: duke@435: case Bytecodes::_dup2: duke@435: case Bytecodes::_dup2_x1: duke@435: case Bytecodes::_dup2_x2: duke@435: case Bytecodes::_swap: duke@435: case Bytecodes::_iadd: duke@435: case Bytecodes::_fadd: duke@435: case Bytecodes::_isub: duke@435: case Bytecodes::_fsub: duke@435: case Bytecodes::_imul: duke@435: case Bytecodes::_fmul: duke@435: case Bytecodes::_idiv: duke@435: case Bytecodes::_fdiv: duke@435: case Bytecodes::_irem: duke@435: case Bytecodes::_frem: duke@435: case Bytecodes::_ishl: duke@435: case Bytecodes::_ishr: duke@435: case Bytecodes::_iushr: duke@435: case Bytecodes::_iand: duke@435: case Bytecodes::_ior: duke@435: case Bytecodes::_ixor: duke@435: case Bytecodes::_l2f: duke@435: case Bytecodes::_l2i: duke@435: case Bytecodes::_d2f: duke@435: case Bytecodes::_d2i: duke@435: case Bytecodes::_fcmpl: duke@435: case Bytecodes::_fcmpg: duke@435: case Bytecodes::_ladd: duke@435: case Bytecodes::_dadd: duke@435: case Bytecodes::_lsub: duke@435: case Bytecodes::_dsub: duke@435: case Bytecodes::_lmul: duke@435: case Bytecodes::_dmul: duke@435: case Bytecodes::_ldiv: duke@435: case Bytecodes::_ddiv: duke@435: case Bytecodes::_lrem: duke@435: case Bytecodes::_drem: duke@435: case Bytecodes::_land: duke@435: case Bytecodes::_lor: duke@435: case Bytecodes::_lxor: duke@435: case Bytecodes::_ineg: duke@435: case Bytecodes::_fneg: duke@435: case Bytecodes::_i2f: duke@435: case Bytecodes::_f2i: duke@435: case Bytecodes::_i2c: duke@435: case Bytecodes::_i2s: duke@435: case Bytecodes::_i2b: duke@435: case Bytecodes::_lneg: duke@435: case Bytecodes::_dneg: duke@435: case Bytecodes::_l2d: duke@435: case Bytecodes::_d2l: duke@435: case Bytecodes::_lshl: duke@435: case Bytecodes::_lshr: duke@435: case Bytecodes::_lushr: duke@435: case Bytecodes::_i2l: duke@435: case Bytecodes::_i2d: duke@435: case Bytecodes::_f2l: duke@435: case Bytecodes::_f2d: duke@435: case Bytecodes::_lcmp: duke@435: case Bytecodes::_dcmpl: duke@435: case Bytecodes::_dcmpg: duke@435: case Bytecodes::_ifeq: duke@435: case Bytecodes::_ifne: duke@435: case Bytecodes::_iflt: duke@435: case Bytecodes::_ifge: duke@435: case Bytecodes::_ifgt: duke@435: case Bytecodes::_ifle: duke@435: case Bytecodes::_tableswitch: duke@435: case Bytecodes::_ireturn: duke@435: case Bytecodes::_freturn: duke@435: case Bytecodes::_if_icmpeq: duke@435: case Bytecodes::_if_icmpne: duke@435: case Bytecodes::_if_icmplt: duke@435: case Bytecodes::_if_icmpge: duke@435: case Bytecodes::_if_icmpgt: duke@435: case Bytecodes::_if_icmple: duke@435: case Bytecodes::_lreturn: duke@435: case Bytecodes::_dreturn: duke@435: case Bytecodes::_if_acmpeq: duke@435: case Bytecodes::_if_acmpne: duke@435: case Bytecodes::_jsr: duke@435: case Bytecodes::_jsr_w: duke@435: case Bytecodes::_getstatic: duke@435: case Bytecodes::_putstatic: duke@435: case Bytecodes::_getfield: duke@435: case Bytecodes::_putfield: duke@435: case Bytecodes::_invokevirtual: duke@435: case Bytecodes::_invokespecial: duke@435: case Bytecodes::_invokestatic: duke@435: case Bytecodes::_invokeinterface: duke@435: case Bytecodes::_newarray: duke@435: case Bytecodes::_anewarray: duke@435: case Bytecodes::_checkcast: duke@435: case Bytecodes::_arraylength: duke@435: case Bytecodes::_instanceof: duke@435: case Bytecodes::_athrow: duke@435: case Bytecodes::_areturn: duke@435: case Bytecodes::_monitorenter: duke@435: case Bytecodes::_monitorexit: duke@435: case Bytecodes::_ifnull: duke@435: case Bytecodes::_ifnonnull: duke@435: case Bytecodes::_multianewarray: duke@435: case Bytecodes::_lookupswitch: duke@435: // These bytecodes have no effect on the method's locals. duke@435: break; duke@435: duke@435: case Bytecodes::_return: duke@435: if (instruction->method()->intrinsic_id() == vmIntrinsics::_Object_init) { duke@435: // return from Object.init implicitly registers a finalizer duke@435: // for the receiver if needed, so keep it alive. duke@435: load_one(0); duke@435: } duke@435: break; duke@435: duke@435: duke@435: case Bytecodes::_lload: duke@435: case Bytecodes::_dload: duke@435: load_two(instruction->get_index()); duke@435: break; duke@435: duke@435: case Bytecodes::_lload_0: duke@435: case Bytecodes::_dload_0: duke@435: load_two(0); duke@435: break; duke@435: duke@435: case Bytecodes::_lload_1: duke@435: case Bytecodes::_dload_1: duke@435: load_two(1); duke@435: break; duke@435: duke@435: case Bytecodes::_lload_2: duke@435: case Bytecodes::_dload_2: duke@435: load_two(2); duke@435: break; duke@435: duke@435: case Bytecodes::_lload_3: duke@435: case Bytecodes::_dload_3: duke@435: load_two(3); duke@435: break; duke@435: duke@435: case Bytecodes::_iload: duke@435: case Bytecodes::_iinc: duke@435: case Bytecodes::_fload: duke@435: case Bytecodes::_aload: duke@435: case Bytecodes::_ret: duke@435: load_one(instruction->get_index()); duke@435: break; duke@435: duke@435: case Bytecodes::_iload_0: duke@435: case Bytecodes::_fload_0: duke@435: case Bytecodes::_aload_0: duke@435: load_one(0); duke@435: break; duke@435: duke@435: case Bytecodes::_iload_1: duke@435: case Bytecodes::_fload_1: duke@435: case Bytecodes::_aload_1: duke@435: load_one(1); duke@435: break; duke@435: duke@435: case Bytecodes::_iload_2: duke@435: case Bytecodes::_fload_2: duke@435: case Bytecodes::_aload_2: duke@435: load_one(2); duke@435: break; duke@435: duke@435: case Bytecodes::_iload_3: duke@435: case Bytecodes::_fload_3: duke@435: case Bytecodes::_aload_3: duke@435: load_one(3); duke@435: break; duke@435: duke@435: case Bytecodes::_lstore: duke@435: case Bytecodes::_dstore: duke@435: store_two(localNum = instruction->get_index()); duke@435: break; duke@435: duke@435: case Bytecodes::_lstore_0: duke@435: case Bytecodes::_dstore_0: duke@435: store_two(0); duke@435: break; duke@435: duke@435: case Bytecodes::_lstore_1: duke@435: case Bytecodes::_dstore_1: duke@435: store_two(1); duke@435: break; duke@435: duke@435: case Bytecodes::_lstore_2: duke@435: case Bytecodes::_dstore_2: duke@435: store_two(2); duke@435: break; duke@435: duke@435: case Bytecodes::_lstore_3: duke@435: case Bytecodes::_dstore_3: duke@435: store_two(3); duke@435: break; duke@435: duke@435: case Bytecodes::_istore: duke@435: case Bytecodes::_fstore: duke@435: case Bytecodes::_astore: duke@435: store_one(instruction->get_index()); duke@435: break; duke@435: duke@435: case Bytecodes::_istore_0: duke@435: case Bytecodes::_fstore_0: duke@435: case Bytecodes::_astore_0: duke@435: store_one(0); duke@435: break; duke@435: duke@435: case Bytecodes::_istore_1: duke@435: case Bytecodes::_fstore_1: duke@435: case Bytecodes::_astore_1: duke@435: store_one(1); duke@435: break; duke@435: duke@435: case Bytecodes::_istore_2: duke@435: case Bytecodes::_fstore_2: duke@435: case Bytecodes::_astore_2: duke@435: store_one(2); duke@435: break; duke@435: duke@435: case Bytecodes::_istore_3: duke@435: case Bytecodes::_fstore_3: duke@435: case Bytecodes::_astore_3: duke@435: store_one(3); duke@435: break; duke@435: duke@435: case Bytecodes::_wide: duke@435: fatal("Iterator should skip this bytecode"); duke@435: break; duke@435: duke@435: default: duke@435: tty->print("unexpected opcode: %d\n", instruction->cur_bc()); duke@435: ShouldNotReachHere(); duke@435: break; duke@435: } duke@435: } duke@435: duke@435: void MethodLiveness::BasicBlock::load_two(int local) { duke@435: load_one(local); duke@435: load_one(local+1); duke@435: } duke@435: duke@435: void MethodLiveness::BasicBlock::load_one(int local) { duke@435: if (!_kill.at(local)) { duke@435: _gen.at_put(local, true); duke@435: } duke@435: } duke@435: duke@435: void MethodLiveness::BasicBlock::store_two(int local) { duke@435: store_one(local); duke@435: store_one(local+1); duke@435: } duke@435: duke@435: void MethodLiveness::BasicBlock::store_one(int local) { duke@435: if (!_gen.at(local)) { duke@435: _kill.at_put(local, true); duke@435: } duke@435: } duke@435: duke@435: void MethodLiveness::BasicBlock::propagate(MethodLiveness *ml) { duke@435: // These set operations could be combined for efficiency if the duke@435: // performance of this analysis becomes an issue. duke@435: _entry.set_union(_normal_exit); duke@435: _entry.set_difference(_kill); duke@435: _entry.set_union(_gen); duke@435: duke@435: // Note that we merge information from our exceptional successors duke@435: // just once, rather than at individual bytecodes. duke@435: _entry.set_union(_exception_exit); duke@435: duke@435: if (TraceLivenessGen) { duke@435: tty->print_cr(" ** Visiting block at %d **", start_bci()); duke@435: print_on(tty); duke@435: } duke@435: duke@435: int i; duke@435: for (i=_normal_predecessors->length()-1; i>=0; i--) { duke@435: BasicBlock *block = _normal_predecessors->at(i); duke@435: if (block->merge_normal(_entry)) { duke@435: ml->work_list_add(block); duke@435: } duke@435: } duke@435: for (i=_exception_predecessors->length()-1; i>=0; i--) { duke@435: BasicBlock *block = _exception_predecessors->at(i); duke@435: if (block->merge_exception(_entry)) { duke@435: ml->work_list_add(block); duke@435: } duke@435: } duke@435: } duke@435: duke@435: bool MethodLiveness::BasicBlock::merge_normal(BitMap other) { duke@435: return _normal_exit.set_union_with_result(other); duke@435: } duke@435: duke@435: bool MethodLiveness::BasicBlock::merge_exception(BitMap other) { duke@435: return _exception_exit.set_union_with_result(other); duke@435: } duke@435: duke@435: MethodLivenessResult MethodLiveness::BasicBlock::get_liveness_at(ciMethod* method, int bci) { duke@435: MethodLivenessResult answer(NEW_RESOURCE_ARRAY(uintptr_t, _analyzer->bit_map_size_words()), duke@435: _analyzer->bit_map_size_bits()); duke@435: answer.set_is_valid(); duke@435: duke@435: #ifndef ASSERT duke@435: if (bci == start_bci()) { duke@435: answer.set_from(_entry); duke@435: return answer; duke@435: } duke@435: #endif duke@435: duke@435: #ifdef ASSERT duke@435: ResourceMark rm; duke@435: BitMap g(_gen.size()); g.set_from(_gen); duke@435: BitMap k(_kill.size()); k.set_from(_kill); duke@435: #endif duke@435: if (_last_bci != bci || trueInDebug) { duke@435: ciBytecodeStream bytes(method); duke@435: bytes.reset_to_bci(bci); duke@435: bytes.set_max_bci(limit_bci()); duke@435: compute_gen_kill_range(&bytes); duke@435: assert(_last_bci != bci || duke@435: (g.is_same(_gen) && k.is_same(_kill)), "cached computation is incorrect"); duke@435: _last_bci = bci; duke@435: } duke@435: duke@435: answer.clear(); duke@435: answer.set_union(_normal_exit); duke@435: answer.set_difference(_kill); duke@435: answer.set_union(_gen); duke@435: answer.set_union(_exception_exit); duke@435: duke@435: #ifdef ASSERT duke@435: if (bci == start_bci()) { duke@435: assert(answer.is_same(_entry), "optimized answer must be accurate"); duke@435: } duke@435: #endif duke@435: duke@435: return answer; duke@435: } duke@435: duke@435: #ifndef PRODUCT duke@435: duke@435: void MethodLiveness::BasicBlock::print_on(outputStream *os) const { duke@435: os->print_cr("==================================================================="); duke@435: os->print_cr(" Block start: %4d, limit: %4d", _start_bci, _limit_bci); duke@435: os->print (" Normal predecessors (%2d) @", _normal_predecessors->length()); duke@435: int i; duke@435: for (i=0; i < _normal_predecessors->length(); i++) { duke@435: os->print(" %4d", _normal_predecessors->at(i)->start_bci()); duke@435: } duke@435: os->cr(); duke@435: os->print (" Exceptional predecessors (%2d) @", _exception_predecessors->length()); duke@435: for (i=0; i < _exception_predecessors->length(); i++) { duke@435: os->print(" %4d", _exception_predecessors->at(i)->start_bci()); duke@435: } duke@435: os->cr(); duke@435: os->print (" Normal Exit : "); duke@435: _normal_exit.print_on(os); duke@435: os->print (" Gen : "); duke@435: _gen.print_on(os); duke@435: os->print (" Kill : "); duke@435: _kill.print_on(os); duke@435: os->print (" Exception Exit: "); duke@435: _exception_exit.print_on(os); duke@435: os->print (" Entry : "); duke@435: _entry.print_on(os); duke@435: } duke@435: duke@435: #endif // PRODUCT