我想知道JVM或JDK如何运行异常。例如,如果我们有数组
int tab[] = {1, 2, 3};
,我们尝试访问
tab[10]
JVM运行ArrayIndexOutOfBoundsException
可以。是否可以查看在JDK或JVM的哪个部分执行此异常?我的意思是throw new ArrayIndexOutOfBoundsException()
或类似的东西?从JNI调用中调用是不可能的吗?
答案 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代码,有很多地方可以查看:
翻译。解释器中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);
}
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
函数。