В каком месте внутри Java запускаются исключения - PullRequest
0 голосов
/ 24 ноября 2018

Интересно, как JVM или JDK запускают исключения.Например, если у нас есть массив

int tab[] = {1, 2, 3};

и мы пытаемся получить доступ к

tab[10]

запуск JVM ArrayIndexOutOfBoundsException, все в порядке.Можно ли увидеть, в какой части JDK или JVM выполняется это исключение?Я имею в виду throw new ArrayIndexOutOfBoundsException() или что-то подобное?Разве это невозможно от вызова для вызовов JNI?

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

Во-первых, см. этот ответ для простого обзора того, как работают исключения в JVM HotSpot.

Что касается кода JVM, который выдает ArrayIndexOutOfBoundsException, есть несколько мест, которые можно увидеть:

  1. Переводчик.Реализация iaload байт-кода в интерпретаторе (а также других байт-кодов доступа к массиву) включает проверку индекса.Если проверка не пройдена, интерпретатор переходит к заглушке, генерирующей исключение.См. templateTable_x86.cpp :

    void TemplateTable::iaload() {
      transition(itos, itos);
      // rax: index
      // rdx: array
      index_check(rdx, rax); // kills rbx                              --------------
      __ access_load_at(T_INT, IN_HEAP | IS_ARRAY, rax,                             |
                        Address(rdx, rax, Address::times_4,                         |
                                arrayOopDesc::base_offset_in_bytes(T_INT)),         |
                        noreg, noreg);                                              |
    }                                                                               |
                                                                                    |
    void TemplateTable::index_check(Register array, Register index) {             <--
      // Pop ptr into array                                                          
      __ pop_ptr(array);                                                             
      index_check_without_pop(array, index);                           --------------
    }                                                                               |
                                                                                    |
    void TemplateTable::index_check_without_pop(Register array, Register index) { <--
      // destroys rbx
      // check array
      __ null_check(array, arrayOopDesc::length_offset_in_bytes());
      // sign extend index for use by indexed load
      __ movl2ptr(index, index);
      // check index
      __ cmpl(index, Address(array, arrayOopDesc::length_offset_in_bytes()));
      if (index != rbx) {
        // ??? convention: move aberrant index into rbx for exception message
        assert(rbx != array, "different registers");
        __ movl(rbx, index);
      }
      Label skip;
      __ jccb(Assembler::below, skip);
      // Pass array to create more detailed exceptions.
      __ mov(NOT_LP64(rax) LP64_ONLY(c_rarg1), array);
      __ jump(ExternalAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry));  !!!
      __ bind(skip);
    }
    
  2. JIT-компиляторы (C1 и C2).Когда метод JIT-компилируется, компилятор включает аналогичную последовательность проверки индекса в производимый машинный код.Иногда, когда компилятор может доказать, что не может возникать какое-либо недопустимое условие, он устраняет избыточную проверку.

    Например, компилятор C1 сначала запускает независимую от платформы проверку диапазона в промежуточном представлении, см. c1_LIRGenerator.cpp :

    void LIRGenerator::array_range_check(LIR_Opr array, LIR_Opr index,
                                        CodeEmitInfo* null_check_info, CodeEmitInfo* range_check_info) {
      CodeStub* stub = new RangeCheckStub(range_check_info, index, array);
      if (index->is_constant()) {
        cmp_mem_int(lir_cond_belowEqual, array, arrayOopDesc::length_offset_in_bytes(),
                    index->as_jint(), null_check_info);
        __ branch(lir_cond_belowEqual, T_INT, stub); // forward branch
      } else {
        cmp_reg_mem(lir_cond_aboveEqual, index, array,
                    arrayOopDesc::length_offset_in_bytes(), T_INT, null_check_info);
        __ branch(lir_cond_aboveEqual, T_INT, stub); // forward branch
      }
    }
    

    Затем во время генерации кода RangeCheckStub расширяется до зависимой от платформы сборки, которая включает в себя заглушку перехода к исключению, см. c1_CodeStubs_x86.cpp :

      if (_throw_index_out_of_bounds_exception) {
        stub_id = Runtime1::throw_index_exception_id;
      } else {
        stub_id = Runtime1::throw_range_check_failed_id;
        ce->store_parameter(_array->as_pointer_register(), 1);
      }
      __ call(RuntimeAddress(Runtime1::entry_for(stub_id)));
    

    Наконец, это приводит к вызову функции Exceptions::_throw в коде JVM C ++.

0 голосов
/ 24 ноября 2018

Исключение ArrayIndexOutOfBoundsException вызывается JVM.Байт-код не проверяет индекс массива:

    int tab[] = {1};
    int x = tab[2];

байт-код для этих двух строк:

    ICONST_1
    NEWARRAY T_INT
    DUP
    ICONST_0
    ICONST_1
    IASTORE
    ASTORE 2
   L3
    LINENUMBER 26 L3
    ALOAD 2
    ICONST_1
    IALOAD   <-- we read element 1 which is out of bounds
    ISTORE 3

, поскольку вы можете видеть, что нет проверки индекса, не генерируется исключение.Это означает, что это сделано JVM

...