我想知道JVM或JDK是如何运行异常的。例如,如果我们有数组
int tab[] = {1,2,3};
我们尝试访问
选项卡[10]
JVM运行ArrayIndexOutOfBoundsException
没问题。是否可以看到该异常在 JDK 或 JVM 的哪个部分执行?我的意思是抛出 new ArrayIndexOutOfBoundsException() 或类似的东西?难道从调用JNI调用就不可能了吗?
最佳答案
首先,参见this answer简单概述异常在 HotSpot JVM 中如何工作。
对于抛出ArrayIndexOutOfBoundsException
的JVM代码,有多个地方可以看到:
口译员。解释器中的 iaload 字节码(以及其他数组访问字节码)的实现包括索引检查。如果检查失败,解释器将跳转到异常抛出 stub 。请参阅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); }
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 扩展为依赖于平台的程序集,其中包括跳转到异常抛出 stub ,请参阅 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++ 代码中的函数。
关于java - java内部在什么地方运行异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53456703/