Example #1
0
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;
}
Example #2
0
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));
    }
  }
}
Example #4
0
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;
          }
        }
      }
    }
  }
}
Example #5
0
// 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);
}