int MultiBranchData::compute_cell_count(BytecodeStream* stream) { int cell_count = 0; if (stream->code() == Bytecodes::_tableswitch) { Bytecode_tableswitch* sw = Bytecode_tableswitch_at(stream->bcp()); cell_count = 1 + per_case_cell_count * (1 + sw->length()); // 1 for default } else { Bytecode_lookupswitch* sw = Bytecode_lookupswitch_at(stream->bcp()); cell_count = 1 + per_case_cell_count * (sw->number_of_pairs() + 1); // 1 for default } return cell_count; }
void MultiBranchData::post_initialize(BytecodeStream* stream, methodDataOop mdo) { assert(stream->bci() == bci(), "wrong pos"); int target; int my_di; int target_di; int offset; if (stream->code() == Bytecodes::_tableswitch) { Bytecode_tableswitch* sw = Bytecode_tableswitch_at(stream->bcp()); int len = sw->length(); assert(array_len() == per_case_cell_count * (len + 1), "wrong len"); for (int count = 0; count < len; count++) { target = sw->dest_offset_at(count) + bci(); my_di = mdo->dp_to_di(dp()); target_di = mdo->bci_to_di(target); offset = target_di - my_di; set_displacement_at(count, offset); } target = sw->default_offset() + bci(); my_di = mdo->dp_to_di(dp()); target_di = mdo->bci_to_di(target); offset = target_di - my_di; set_default_displacement(offset); } else { Bytecode_lookupswitch* sw = Bytecode_lookupswitch_at(stream->bcp()); int npairs = sw->number_of_pairs(); assert(array_len() == per_case_cell_count * (npairs + 1), "wrong len"); for (int count = 0; count < npairs; count++) { LookupswitchPair *pair = sw->pair_at(count); target = pair->offset() + bci(); my_di = mdo->dp_to_di(dp()); target_di = mdo->bci_to_di(target); offset = target_di - my_di; set_displacement_at(count, offset); } target = sw->default_offset() + bci(); my_di = mdo->dp_to_di(dp()); target_di = mdo->bci_to_di(target); offset = target_di - my_di; set_default_displacement(offset); } }
void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, GrowableArray<ciBlock *> &successors) { blk->set_processed(); ciBytecodeStream s(method()); int limit_bci = blk->limit_bci(); bool fall_through = false; ArgumentMap allocated_obj; allocated_obj.add_allocated(); ArgumentMap unknown_obj; unknown_obj.add_unknown(); ArgumentMap empty_map; s.reset_to_bci(blk->start_bci()); while (s.next() != ciBytecodeStream::EOBC() && s.cur_bci() < limit_bci) { fall_through = true; switch (s.cur_bc()) { case Bytecodes::_nop: break; case Bytecodes::_aconst_null: state.apush(empty_map); break; case Bytecodes::_iconst_m1: case Bytecodes::_iconst_0: case Bytecodes::_iconst_1: case Bytecodes::_iconst_2: case Bytecodes::_iconst_3: case Bytecodes::_iconst_4: case Bytecodes::_iconst_5: case Bytecodes::_fconst_0: case Bytecodes::_fconst_1: case Bytecodes::_fconst_2: case Bytecodes::_bipush: case Bytecodes::_sipush: state.spush(); break; case Bytecodes::_lconst_0: case Bytecodes::_lconst_1: case Bytecodes::_dconst_0: case Bytecodes::_dconst_1: state.lpush(); break; case Bytecodes::_ldc: case Bytecodes::_ldc_w: case Bytecodes::_ldc2_w: if (type2size[s.get_constant().basic_type()] == 1) { state.spush(); } else { state.lpush(); } break; case Bytecodes::_aload: state.apush(state._vars[s.get_index()]); break; case Bytecodes::_iload: case Bytecodes::_fload: case Bytecodes::_iload_0: case Bytecodes::_iload_1: case Bytecodes::_iload_2: case Bytecodes::_iload_3: case Bytecodes::_fload_0: case Bytecodes::_fload_1: case Bytecodes::_fload_2: case Bytecodes::_fload_3: state.spush(); break; case Bytecodes::_lload: case Bytecodes::_dload: case Bytecodes::_lload_0: case Bytecodes::_lload_1: case Bytecodes::_lload_2: case Bytecodes::_lload_3: case Bytecodes::_dload_0: case Bytecodes::_dload_1: case Bytecodes::_dload_2: case Bytecodes::_dload_3: state.lpush(); break; case Bytecodes::_aload_0: state.apush(state._vars[0]); break; case Bytecodes::_aload_1: state.apush(state._vars[1]); break; case Bytecodes::_aload_2: state.apush(state._vars[2]); break; case Bytecodes::_aload_3: state.apush(state._vars[3]); break; case Bytecodes::_iaload: case Bytecodes::_faload: case Bytecodes::_baload: case Bytecodes::_caload: case Bytecodes::_saload: state.spop(); set_method_escape(state.apop()); state.spush(); break; case Bytecodes::_laload: case Bytecodes::_daload: state.spop(); set_method_escape(state.apop()); state.lpush(); break; case Bytecodes::_aaload: { state.spop(); ArgumentMap array = state.apop(); set_method_escape(array); state.apush(unknown_obj); set_dirty(array); } break; case Bytecodes::_istore: case Bytecodes::_fstore: case Bytecodes::_istore_0: case Bytecodes::_istore_1: case Bytecodes::_istore_2: case Bytecodes::_istore_3: case Bytecodes::_fstore_0: case Bytecodes::_fstore_1: case Bytecodes::_fstore_2: case Bytecodes::_fstore_3: state.spop(); break; case Bytecodes::_lstore: case Bytecodes::_dstore: case Bytecodes::_lstore_0: case Bytecodes::_lstore_1: case Bytecodes::_lstore_2: case Bytecodes::_lstore_3: case Bytecodes::_dstore_0: case Bytecodes::_dstore_1: case Bytecodes::_dstore_2: case Bytecodes::_dstore_3: state.lpop(); break; case Bytecodes::_astore: state._vars[s.get_index()] = state.apop(); break; case Bytecodes::_astore_0: state._vars[0] = state.apop(); break; case Bytecodes::_astore_1: state._vars[1] = state.apop(); break; case Bytecodes::_astore_2: state._vars[2] = state.apop(); break; case Bytecodes::_astore_3: state._vars[3] = state.apop(); break; case Bytecodes::_iastore: case Bytecodes::_fastore: case Bytecodes::_bastore: case Bytecodes::_castore: case Bytecodes::_sastore: { state.spop(); state.spop(); ArgumentMap arr = state.apop(); set_method_escape(arr); break; } case Bytecodes::_lastore: case Bytecodes::_dastore: { state.lpop(); state.spop(); ArgumentMap arr = state.apop(); set_method_escape(arr); break; } case Bytecodes::_aastore: { set_global_escape(state.apop()); state.spop(); ArgumentMap arr = state.apop(); break; } case Bytecodes::_pop: state.raw_pop(); break; case Bytecodes::_pop2: state.raw_pop(); state.raw_pop(); break; case Bytecodes::_dup: { ArgumentMap w1 = state.raw_pop(); state.raw_push(w1); state.raw_push(w1); } break; case Bytecodes::_dup_x1: { ArgumentMap w1 = state.raw_pop(); ArgumentMap w2 = state.raw_pop(); state.raw_push(w1); state.raw_push(w2); state.raw_push(w1); } break; case Bytecodes::_dup_x2: { ArgumentMap w1 = state.raw_pop(); ArgumentMap w2 = state.raw_pop(); ArgumentMap w3 = state.raw_pop(); state.raw_push(w1); state.raw_push(w3); state.raw_push(w2); state.raw_push(w1); } break; case Bytecodes::_dup2: { ArgumentMap w1 = state.raw_pop(); ArgumentMap w2 = state.raw_pop(); state.raw_push(w2); state.raw_push(w1); state.raw_push(w2); state.raw_push(w1); } break; case Bytecodes::_dup2_x1: { ArgumentMap w1 = state.raw_pop(); ArgumentMap w2 = state.raw_pop(); ArgumentMap w3 = state.raw_pop(); state.raw_push(w2); state.raw_push(w1); state.raw_push(w3); state.raw_push(w2); state.raw_push(w1); } break; case Bytecodes::_dup2_x2: { ArgumentMap w1 = state.raw_pop(); ArgumentMap w2 = state.raw_pop(); ArgumentMap w3 = state.raw_pop(); ArgumentMap w4 = state.raw_pop(); state.raw_push(w2); state.raw_push(w1); state.raw_push(w4); state.raw_push(w3); state.raw_push(w2); state.raw_push(w1); } break; case Bytecodes::_swap: { ArgumentMap w1 = state.raw_pop(); ArgumentMap w2 = state.raw_pop(); state.raw_push(w1); state.raw_push(w2); } break; case Bytecodes::_iadd: case Bytecodes::_fadd: case Bytecodes::_isub: case Bytecodes::_fsub: case Bytecodes::_imul: case Bytecodes::_fmul: case Bytecodes::_idiv: case Bytecodes::_fdiv: case Bytecodes::_irem: case Bytecodes::_frem: case Bytecodes::_iand: case Bytecodes::_ior: case Bytecodes::_ixor: state.spop(); state.spop(); state.spush(); break; case Bytecodes::_ladd: case Bytecodes::_dadd: case Bytecodes::_lsub: case Bytecodes::_dsub: case Bytecodes::_lmul: case Bytecodes::_dmul: case Bytecodes::_ldiv: case Bytecodes::_ddiv: case Bytecodes::_lrem: case Bytecodes::_drem: case Bytecodes::_land: case Bytecodes::_lor: case Bytecodes::_lxor: state.lpop(); state.lpop(); state.lpush(); break; case Bytecodes::_ishl: case Bytecodes::_ishr: case Bytecodes::_iushr: state.spop(); state.spop(); state.spush(); break; case Bytecodes::_lshl: case Bytecodes::_lshr: case Bytecodes::_lushr: state.spop(); state.lpop(); state.lpush(); break; case Bytecodes::_ineg: case Bytecodes::_fneg: state.spop(); state.spush(); break; case Bytecodes::_lneg: case Bytecodes::_dneg: state.lpop(); state.lpush(); break; case Bytecodes::_iinc: break; case Bytecodes::_i2l: case Bytecodes::_i2d: case Bytecodes::_f2l: case Bytecodes::_f2d: state.spop(); state.lpush(); break; case Bytecodes::_i2f: case Bytecodes::_f2i: state.spop(); state.spush(); break; case Bytecodes::_l2i: case Bytecodes::_l2f: case Bytecodes::_d2i: case Bytecodes::_d2f: state.lpop(); state.spush(); break; case Bytecodes::_l2d: case Bytecodes::_d2l: state.lpop(); state.lpush(); break; case Bytecodes::_i2b: case Bytecodes::_i2c: case Bytecodes::_i2s: state.spop(); state.spush(); break; case Bytecodes::_lcmp: case Bytecodes::_dcmpl: case Bytecodes::_dcmpg: state.lpop(); state.lpop(); state.spush(); break; case Bytecodes::_fcmpl: case Bytecodes::_fcmpg: state.spop(); state.spop(); state.spush(); break; case Bytecodes::_ifeq: case Bytecodes::_ifne: case Bytecodes::_iflt: case Bytecodes::_ifge: case Bytecodes::_ifgt: case Bytecodes::_ifle: { state.spop(); int dest_bci = s.get_dest(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); assert(s.next_bci() == limit_bci, "branch must end block"); successors.push(_methodBlocks->block_containing(dest_bci)); break; } case Bytecodes::_if_icmpeq: case Bytecodes::_if_icmpne: case Bytecodes::_if_icmplt: case Bytecodes::_if_icmpge: case Bytecodes::_if_icmpgt: case Bytecodes::_if_icmple: { state.spop(); state.spop(); int dest_bci = s.get_dest(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); assert(s.next_bci() == limit_bci, "branch must end block"); successors.push(_methodBlocks->block_containing(dest_bci)); break; } case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne: { set_method_escape(state.apop()); set_method_escape(state.apop()); int dest_bci = s.get_dest(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); assert(s.next_bci() == limit_bci, "branch must end block"); successors.push(_methodBlocks->block_containing(dest_bci)); break; } case Bytecodes::_goto: { int dest_bci = s.get_dest(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); assert(s.next_bci() == limit_bci, "branch must end block"); successors.push(_methodBlocks->block_containing(dest_bci)); fall_through = false; break; } case Bytecodes::_jsr: { int dest_bci = s.get_dest(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); assert(s.next_bci() == limit_bci, "branch must end block"); state.apush(empty_map); successors.push(_methodBlocks->block_containing(dest_bci)); fall_through = false; break; } case Bytecodes::_ret: // we don't track the destination of a "ret" instruction assert(s.next_bci() == limit_bci, "branch must end block"); fall_through = false; break; case Bytecodes::_return: assert(s.next_bci() == limit_bci, "return must end block"); fall_through = false; break; case Bytecodes::_tableswitch: { state.spop(); Bytecode_tableswitch* switch_ = Bytecode_tableswitch_at(s.cur_bcp()); int len = switch_->length(); int dest_bci; for (int i = 0; i < len; i++) { dest_bci = s.cur_bci() + switch_->dest_offset_at(i); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); successors.push(_methodBlocks->block_containing(dest_bci)); } dest_bci = s.cur_bci() + switch_->default_offset(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); successors.push(_methodBlocks->block_containing(dest_bci)); assert(s.next_bci() == limit_bci, "branch must end block"); fall_through = false; break; } case Bytecodes::_lookupswitch: { state.spop(); Bytecode_lookupswitch* switch_ = Bytecode_lookupswitch_at(s.cur_bcp()); int len = switch_->number_of_pairs(); int dest_bci; for (int i = 0; i < len; i++) { dest_bci = s.cur_bci() + switch_->pair_at(i)->offset(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); successors.push(_methodBlocks->block_containing(dest_bci)); } dest_bci = s.cur_bci() + switch_->default_offset(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); successors.push(_methodBlocks->block_containing(dest_bci)); fall_through = false; break; } case Bytecodes::_ireturn: case Bytecodes::_freturn: state.spop(); fall_through = false; break; case Bytecodes::_lreturn: case Bytecodes::_dreturn: state.lpop(); fall_through = false; break; case Bytecodes::_areturn: set_returned(state.apop()); fall_through = false; break; case Bytecodes::_getstatic: case Bytecodes::_getfield: { bool will_link; ciField* field = s.get_field(will_link); BasicType field_type = field->type()->basic_type(); if (s.cur_bc() != Bytecodes::_getstatic) { set_method_escape(state.apop()); } if (field_type == T_OBJECT || field_type == T_ARRAY) { state.apush(unknown_obj); } else if (type2size[field_type] == 1) { state.spush(); } else { state.lpush(); } } break; case Bytecodes::_putstatic: case Bytecodes::_putfield: { bool will_link; ciField* field = s.get_field(will_link); BasicType field_type = field->type()->basic_type(); if (field_type == T_OBJECT || field_type == T_ARRAY) { set_global_escape(state.apop()); } else if (type2size[field_type] == 1) { state.spop(); } else { state.lpop(); } if (s.cur_bc() != Bytecodes::_putstatic) { ArgumentMap p = state.apop(); set_method_escape(p); } } break; case Bytecodes::_invokevirtual: case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: case Bytecodes::_invokeinterface: { bool will_link; ciMethod* target = s.get_method(will_link); ciKlass* holder = s.get_declared_method_holder(); invoke(state, s.cur_bc(), target, holder); ciType* return_type = target->return_type(); if (!return_type->is_primitive_type()) { state.apush(unknown_obj); } else if (return_type->is_one_word()) { state.spush(); } else if (return_type->is_two_word()) { state.lpush(); } } break; case Bytecodes::_xxxunusedxxx: ShouldNotReachHere(); break; case Bytecodes::_new: state.apush(allocated_obj); break; case Bytecodes::_newarray: case Bytecodes::_anewarray: state.spop(); state.apush(allocated_obj); break; case Bytecodes::_multianewarray: { int i = s.cur_bcp()[3]; while (i-- > 0) state.spop(); state.apush(allocated_obj); } break; case Bytecodes::_arraylength: set_method_escape(state.apop()); state.spush(); break; case Bytecodes::_athrow: set_global_escape(state.apop()); fall_through = false; break; case Bytecodes::_checkcast: { ArgumentMap obj = state.apop(); set_method_escape(obj); state.apush(obj); } break; case Bytecodes::_instanceof: set_method_escape(state.apop()); state.spush(); break; case Bytecodes::_monitorenter: case Bytecodes::_monitorexit: state.apop(); break; case Bytecodes::_wide: ShouldNotReachHere(); break; case Bytecodes::_ifnull: case Bytecodes::_ifnonnull: { set_method_escape(state.apop()); int dest_bci = s.get_dest(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); assert(s.next_bci() == limit_bci, "branch must end block"); successors.push(_methodBlocks->block_containing(dest_bci)); break; } case Bytecodes::_goto_w: { int dest_bci = s.get_far_dest(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); assert(s.next_bci() == limit_bci, "branch must end block"); successors.push(_methodBlocks->block_containing(dest_bci)); fall_through = false; break; } case Bytecodes::_jsr_w: { int dest_bci = s.get_far_dest(); assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block"); assert(s.next_bci() == limit_bci, "branch must end block"); state.apush(empty_map); successors.push(_methodBlocks->block_containing(dest_bci)); fall_through = false; break; } case Bytecodes::_breakpoint: break; default: ShouldNotReachHere(); break; } } if (fall_through) { int fall_through_bci = s.cur_bci(); if (fall_through_bci < _method->code_size()) { assert(_methodBlocks->is_block_start(fall_through_bci), "must fall through to block start."); successors.push(_methodBlocks->block_containing(fall_through_bci)); } } }
MethodLiveness::MethodLiveness(Arena* arena, ciMethod* method) #ifdef COMPILER1 : _bci_block_start((uintptr_t*)arena->Amalloc((method->code_size() >> LogBitsPerByte) + 1), method->code_size()) #endif { _arena = arena; _method = method; _bit_map_size_bits = method->max_locals(); _bit_map_size_words = (_bit_map_size_bits / sizeof(unsigned int)) + 1; #ifdef COMPILER1 _bci_block_start.clear(); #endif } void MethodLiveness::compute_liveness() { #ifndef PRODUCT if (TraceLivenessGen) { tty->print_cr("################################################################"); tty->print("# Computing liveness information for "); method()->print_short_name(); } if (TimeLivenessAnalysis) _time_total.start(); #endif { TraceTime buildGraph(NULL, &_time_build_graph, TimeLivenessAnalysis); init_basic_blocks(); } { TraceTime genKill(NULL, &_time_gen_kill, TimeLivenessAnalysis); init_gen_kill(); } { TraceTime flow(NULL, &_time_flow, TimeLivenessAnalysis); propagate_liveness(); } #ifndef PRODUCT if (TimeLivenessAnalysis) _time_total.stop(); if (TimeLivenessAnalysis) { // Collect statistics _total_bytes += method()->code_size(); _total_methods++; int num_blocks = _block_count; _total_blocks += num_blocks; _max_method_blocks = MAX2(num_blocks,_max_method_blocks); for (int i=0; i<num_blocks; i++) { BasicBlock *block = _block_list[i]; int numEdges = block->_normal_predecessors->length(); int numExcEdges = block->_exception_predecessors->length(); _total_edges += numEdges; _total_exc_edges += numExcEdges; _max_block_edges = MAX2(numEdges,_max_block_edges); _max_block_exc_edges = MAX2(numExcEdges,_max_block_exc_edges); } int numLocals = _bit_map_size_bits; _total_method_locals += numLocals; _max_method_locals = MAX2(numLocals,_max_method_locals); } #endif } void MethodLiveness::init_basic_blocks() { bool bailout = false; int method_len = method()->code_size(); ciMethodBlocks *mblocks = method()->get_method_blocks(); // Create an array to store the bci->BasicBlock mapping. _block_map = new (arena()) GrowableArray<BasicBlock*>(arena(), method_len, method_len, NULL); _block_count = mblocks->num_blocks(); _block_list = (BasicBlock **) arena()->Amalloc(sizeof(BasicBlock *) * _block_count); // Used for patching up jsr/ret control flow. GrowableArray<BasicBlock*>* jsr_exit_list = new GrowableArray<BasicBlock*>(5); GrowableArray<BasicBlock*>* ret_list = new GrowableArray<BasicBlock*>(5); // generate our block list from ciMethodBlocks for (int blk = 0; blk < _block_count; blk++) { ciBlock *cib = mblocks->block(blk); int start_bci = cib->start_bci(); _block_list[blk] = new (arena()) BasicBlock(this, start_bci, cib->limit_bci()); _block_map->at_put(start_bci, _block_list[blk]); #ifdef COMPILER1 // mark all bcis where a new basic block starts _bci_block_start.set_bit(start_bci); #endif // COMPILER1 } // fill in the predecessors of blocks ciBytecodeStream bytes(method()); for (int blk = 0; blk < _block_count; blk++) { BasicBlock *current_block = _block_list[blk]; int bci = mblocks->block(blk)->control_bci(); if (bci == ciBlock::fall_through_bci) { int limit = current_block->limit_bci(); if (limit < method_len) { BasicBlock *next = _block_map->at(limit); assert( next != NULL, "must be a block immediately following this one."); next->add_normal_predecessor(current_block); } continue; } bytes.reset_to_bci(bci); Bytecodes::Code code = bytes.next(); BasicBlock *dest; // Now we need to interpret the instruction's effect // on control flow. assert (current_block != NULL, "we must have a current block"); switch (code) { 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: // Two way branch. Set predecessors at each destination. dest = _block_map->at(bytes.next_bci()); assert(dest != NULL, "must be a block immediately following this one."); dest->add_normal_predecessor(current_block); dest = _block_map->at(bytes.get_dest()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); break; case Bytecodes::_goto: dest = _block_map->at(bytes.get_dest()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); break; case Bytecodes::_goto_w: dest = _block_map->at(bytes.get_far_dest()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); break; case Bytecodes::_tableswitch: { Bytecode_tableswitch *tableswitch = Bytecode_tableswitch_at(bytes.cur_bcp()); int len = tableswitch->length(); dest = _block_map->at(bci + tableswitch->default_offset()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); while (--len >= 0) { dest = _block_map->at(bci + tableswitch->dest_offset_at(len)); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); } break; } case Bytecodes::_lookupswitch: { Bytecode_lookupswitch *lookupswitch = Bytecode_lookupswitch_at(bytes.cur_bcp()); int npairs = lookupswitch->number_of_pairs(); dest = _block_map->at(bci + lookupswitch->default_offset()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); while(--npairs >= 0) { LookupswitchPair *pair = lookupswitch->pair_at(npairs); dest = _block_map->at( bci + pair->offset()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); } break; } case Bytecodes::_jsr: { assert(bytes.is_wide()==false, "sanity check"); dest = _block_map->at(bytes.get_dest()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); BasicBlock *jsrExit = _block_map->at(current_block->limit_bci()); assert(jsrExit != NULL, "jsr return bci must start a block."); jsr_exit_list->append(jsrExit); break; } case Bytecodes::_jsr_w: { dest = _block_map->at(bytes.get_far_dest()); assert(dest != NULL, "branch desination must start a block."); dest->add_normal_predecessor(current_block); BasicBlock *jsrExit = _block_map->at(current_block->limit_bci()); assert(jsrExit != NULL, "jsr return bci must start a block."); jsr_exit_list->append(jsrExit); break; } case Bytecodes::_wide: assert(false, "wide opcodes should not be seen here"); break; case Bytecodes::_athrow: case Bytecodes::_ireturn: case Bytecodes::_lreturn: case Bytecodes::_freturn: case Bytecodes::_dreturn: case Bytecodes::_areturn: case Bytecodes::_return: // These opcodes are not the normal predecessors of any other opcodes. break; case Bytecodes::_ret: // We will patch up jsr/rets in a subsequent pass. ret_list->append(current_block); break; case Bytecodes::_breakpoint: // Bail out of there are breakpoints in here. bailout = true; break; default: // Do nothing. break; } } // Patch up the jsr/ret's. We conservatively assume that any ret // can return to any jsr site. int ret_list_len = ret_list->length(); int jsr_exit_list_len = jsr_exit_list->length(); if (ret_list_len > 0 && jsr_exit_list_len > 0) { for (int i = jsr_exit_list_len - 1; i >= 0; i--) { BasicBlock *jsrExit = jsr_exit_list->at(i); for (int i = ret_list_len - 1; i >= 0; i--) { jsrExit->add_normal_predecessor(ret_list->at(i)); } } } // Compute exception edges. for (int b=_block_count-1; b >= 0; b--) { BasicBlock *block = _block_list[b]; int block_start = block->start_bci(); int block_limit = block->limit_bci(); ciExceptionHandlerStream handlers(method()); for (; !handlers.is_done(); handlers.next()) { ciExceptionHandler* handler = handlers.handler(); int start = handler->start(); int limit = handler->limit(); int handler_bci = handler->handler_bci(); int intersect_start = MAX2(block_start, start); int intersect_limit = MIN2(block_limit, limit); if (intersect_start < intersect_limit) { // The catch range has a nonempty intersection with this // basic block. That means this basic block can be an // exceptional predecessor. _block_map->at(handler_bci)->add_exception_predecessor(block); if (handler->is_catch_all()) { // This is a catch-all block. if (intersect_start == block_start && intersect_limit == block_limit) { // The basic block is entirely contained in this catch-all block. // Skip the rest of the exception handlers -- they can never be // reached in execution. break; } } } } } }
// Rewrites a method given the index_map information void Rewriter::scan_method(methodOop method) { int nof_jsrs = 0; bool has_monitor_bytecodes = false; { // We cannot tolerate a GC in this block, because we've // cached the bytecodes in 'code_base'. If the methodOop // moves, the bytecodes will also move. No_Safepoint_Verifier nsv; Bytecodes::Code c; // Bytecodes and their length const address code_base = method->code_base(); const int code_length = method->code_size(); int bc_length; for (int bci = 0; bci < code_length; bci += bc_length) { address bcp = code_base + bci; int prefix_length = 0; c = (Bytecodes::Code)(*bcp); // Since we have the code, see if we can get the length // directly. Some more complicated bytecodes will report // a length of zero, meaning we need to make another method // call to calculate the length. bc_length = Bytecodes::length_for(c); if (bc_length == 0) { bc_length = Bytecodes::length_at(bcp); // length_at will put us at the bytecode after the one modified // by 'wide'. We don't currently examine any of the bytecodes // modified by wide, but in case we do in the future... if (c == Bytecodes::_wide) { prefix_length = 1; c = (Bytecodes::Code)bcp[1]; } } assert(bc_length != 0, "impossible bytecode length"); switch (c) { case Bytecodes::_lookupswitch : { #ifndef CC_INTERP Bytecode_lookupswitch* bc = Bytecode_lookupswitch_at(bcp); bc->set_code( bc->number_of_pairs() < BinarySwitchThreshold ? Bytecodes::_fast_linearswitch : Bytecodes::_fast_binaryswitch ); #endif break; } case Bytecodes::_getstatic : // fall through case Bytecodes::_putstatic : // fall through case Bytecodes::_getfield : // fall through case Bytecodes::_putfield : // fall through case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : case Bytecodes::_invokeinterface: rewrite_member_reference(bcp, prefix_length+1); break; case Bytecodes::_invokedynamic: rewrite_invokedynamic(bcp, prefix_length+1, int(sizeof"@@@@DELETE ME")); break; case Bytecodes::_jsr : // fall through case Bytecodes::_jsr_w : nof_jsrs++; break; case Bytecodes::_monitorenter : // fall through case Bytecodes::_monitorexit : has_monitor_bytecodes = true; break; } } } // Update access flags if (has_monitor_bytecodes) { method->set_has_monitor_bytecodes(); } // The present of a jsr bytecode implies that the method might potentially // have to be rewritten, so we run the oopMapGenerator on the method if (nof_jsrs > 0) { method->set_has_jsrs(); // Second pass will revisit this method. assert(method->has_jsrs(), ""); } }
void MethodLiveness::init_basic_blocks() { bool bailout = false; int method_len = method()->code_size(); // Create an array to store the bci->BasicBlock mapping. _block_map = new (arena()) GrowableArray<BasicBlock*>(arena(), method_len, method_len, NULL); _block_list = new (arena()) GrowableArray<BasicBlock*>(arena(), 128, 0, NULL); // Used for patching up jsr/ret control flow. GrowableArray<BasicBlock*>* jsr_exit_list = new GrowableArray<BasicBlock*>(5); GrowableArray<BasicBlock*>* ret_list = new GrowableArray<BasicBlock*>(5); // Make blocks begin at all exception handling instructions. { ciExceptionHandlerStream handlers(method()); for (; !handlers.is_done(); handlers.next()) { ciExceptionHandler* handler = handlers.handler(); int handler_bci = handler->handler_bci(); make_block_at(handler_bci, NULL); } } BasicBlock *current_block = NULL; ciByteCodeStream bytes(method()); Bytecodes::Code code; while ((code = bytes.next()) != ciByteCodeStream::EOBC && !bailout) { int bci = bytes.cur_bci(); // Should we start a new block here? BasicBlock *other = _block_map->at(bci); if (other == NULL) { // This bci has not yet been marked as the start of // a new basic block. If current_block is NULL, then // we are beginning a new block. Otherwise, we continue // with the old block. if (current_block == NULL) { // Make a new block with no predecessors. current_block = make_block_at(bci, NULL); } // Mark this index as belonging to the current block. _block_map->at_put(bci, current_block); } else { // This bci has been marked as the start of a new basic // block. if (current_block != NULL) { other->add_normal_predecessor(current_block); current_block->set_limit_bci(bci); } current_block = other; } // Now we need to interpret the instruction's effect // on control flow. switch (code) { assert (current_block != NULL, "we must have a current block"); 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: // Two way branch. Make a new block at each destination. make_block_at(bytes.next_bci(), current_block); make_block_at(bytes.get_dest(), current_block); current_block->set_limit_bci(bytes.next_bci()); current_block = NULL; break; case Bytecodes::_goto: make_block_at(bytes.get_dest(), current_block); current_block->set_limit_bci(bytes.next_bci()); current_block = NULL; break; case Bytecodes::_goto_w: make_block_at(bytes.get_far_dest(), current_block); current_block->set_limit_bci(bytes.next_bci()); current_block = NULL; break; case Bytecodes::_tableswitch: { Bytecode_tableswitch *tableswitch = Bytecode_tableswitch_at(bytes.cur_bcp()); int len = tableswitch->length(); make_block_at(bci + tableswitch->default_offset(), current_block); while (--len >= 0) { make_block_at(bci + tableswitch->dest_offset_at(len), current_block); } current_block->set_limit_bci(bytes.next_bci()); current_block = NULL; break; } // Some synthetic opcodes here case Bytecodes::_fast_linearswitch: case Bytecodes::_fast_binaryswitch: case Bytecodes::_lookupswitch: { Bytecode_lookupswitch *lookupswitch = Bytecode_lookupswitch_at(bytes.cur_bcp()); int npairs = lookupswitch->number_of_pairs(); make_block_at(bci + lookupswitch->default_offset(), current_block); while(--npairs >= 0) { LookupswitchPair *pair = lookupswitch->pair_at(npairs); make_block_at(bci + pair->offset(), current_block); } current_block->set_limit_bci(bytes.next_bci()); current_block = NULL; break; } case Bytecodes::_jsr: { assert(bytes.is_wide()==false, "sanity check"); make_block_at(bytes.get_dest(), current_block); BasicBlock *jsrExit = make_block_at(bci + 3, NULL); jsr_exit_list->append(jsrExit); current_block->set_limit_bci(bytes.next_bci()); current_block = NULL; break; } case Bytecodes::_jsr_w: { make_block_at(bytes.get_far_dest(), current_block); BasicBlock *jsrExit = make_block_at(bci + 5, NULL); jsr_exit_list->append(jsrExit); current_block->set_limit_bci(bytes.next_bci()); current_block = NULL; break; } case Bytecodes::_wide: assert(false, "wide opcodes should not be seen here"); break; case Bytecodes::_athrow: case Bytecodes::_ireturn: case Bytecodes::_lreturn: case Bytecodes::_freturn: case Bytecodes::_dreturn: case Bytecodes::_areturn: case Bytecodes::_return: // We are done with the current block. These opcodes are // not the normal predecessors of any other opcodes. current_block->set_limit_bci(bytes.next_bci()); current_block = NULL; break; case Bytecodes::_ret: // We will patch up jsr/rets in a subsequent pass. ret_list->append(current_block); current_block->set_limit_bci(bytes.next_bci()); current_block = NULL; break; case Bytecodes::_breakpoint: // Bail out of there are breakpoints in here. bailout = true; break; default: // Do nothing. break; } } if (bailout) { _block_list->clear(); _block_map = NULL; // do not use this field now! return; } // Patch up the jsr/ret's. We conservatively assume that any ret // can return to any jsr site. int ret_list_len = ret_list->length(); int jsr_exit_list_len = jsr_exit_list->length(); if (ret_list_len > 0 && jsr_exit_list_len > 0) { for (int i = jsr_exit_list_len - 1; i >= 0; i--) { BasicBlock *jsrExit = jsr_exit_list->at(i); for (int i = ret_list_len - 1; i >= 0; i--) { jsrExit->add_normal_predecessor(ret_list->at(i)); } } } // Compute exception edges. for (int b=_block_list->length()-1; b >= 0; b--) { BasicBlock *block = _block_list->at(b); int block_start = block->start_bci(); int block_limit = block->limit_bci(); ciExceptionHandlerStream handlers(method()); for (; !handlers.is_done(); handlers.next()) { ciExceptionHandler* handler = handlers.handler(); int start = handler->start(); int limit = handler->limit(); int handler_bci = handler->handler_bci(); int intersect_start = MAX2(block_start, start); int intersect_limit = MIN2(block_limit, limit); if (intersect_start < intersect_limit) { // The catch range has a nonempty intersection with this // basic block. That means this basic block can be an // exceptional predecessor. _block_map->at(handler_bci)->add_exception_predecessor(block); if (handler->is_catch_all()) { // This is a catch-all block. if (intersect_start == block_start && intersect_limit == block_limit) { // The basic block is entirely contained in this catch-all block. // Skip the rest of the exception handlers -- they can never be // reached in execution. break; } } } } } }
void ciMethodBlocks::do_analysis() { ciBytecodeStream s(_method); ciBlock *cur_block = block_containing(0); int limit_bci = _method->code_size(); 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); 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); 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* switch_ = Bytecode_tableswitch_at(s.cur_bcp()); int len = switch_->length(); ciBlock *dest; int dest_bci; for (int i = 0; i < len; i++) { dest_bci = s.cur_bci() + switch_->dest_offset_at(i); dest = make_block_at(dest_bci); } dest_bci = s.cur_bci() + switch_->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* switch_ = Bytecode_lookupswitch_at(s.cur_bcp()); int len = switch_->number_of_pairs(); ciBlock *dest; int dest_bci; for (int i = 0; i < len; i++) { dest_bci = s.cur_bci() + switch_->pair_at(i)->offset(); dest = make_block_at(dest_bci); } dest_bci = s.cur_bci() + switch_->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); 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; } } // End the last block cur_block->set_limit_bci(limit_bci); }