Java在内部运行异常的位置

时间:2018-11-24 09:04:57

标签: java jvm java-native-interface

我想知道JVM或JDK如何运行异常。例如,如果我们有数组

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

,我们尝试访问

tab[10]

JVM运行ArrayIndexOutOfBoundsException可以。是否可以查看在JDK或JVM的哪个部分执行此异常?我的意思是throw new ArrayIndexOutOfBoundsException()或类似的东西?从JNI调用中调用是不可能的吗?

2 个答案:

答案 0 :(得分:1)

ArrayIndexOutOfBoundsException由JVM引发。字节码不检查数组索引:

''' Question #1: Does Public myGobalVar As Integer need to be re-defined when a run-time error occurs?
Public myGobalVar As Integer

Sub Application_Startup()
    Call InitializeGobalVar()
End Sub

Sub InitializeGobalVar()
    myGobalVar = 3
End Sub

Sub One_in_many_mySubs()
On Error Goto ErrHandler_myGobalVar
    Dim objApp as Outlook.Application
    Set objApp as Application

    msgbox myGlobalVar

    ' erroneous event may occur somewhere in the code

    Err.Clear
    ' skip ErrHandler_myGobalVar and exit sub after set objApp = Nothing

ErrHandler_myGobalVar:
    if Err.number <> 0 then

    ''' Question #2: How do I automatically restart InitializeGobalVar whenever a run-time error occurs in the code?
        Call InitializeGobalVar

        MsgBox Err.Description
    end if

    Set objApp = Nothing
End Sub
这两行的

字节码:

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

如您所见,没有索引检查,也没有抛出异常。这意味着它是通过JVM

完成的

答案 1 :(得分:1)

首先,请参见this answer,以简要了解异常在HotSpot JVM中如何工作。

关于抛出ArrayIndexOutOfBoundsException的JVM代码,有很多地方可以查看:

  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)));
    

    最后,这导致在JVM C ++代码中调用Exceptions::_throw函数。