内部在哪个地方java 运行异常
In which place internally java run Exceptions
我想知道 JVM 或 JDK 运行 是如何出现异常的。例如,如果我们有数组
int tab[] = {1, 2, 3};
我们尝试访问
tab[10]
JVM 运行 ArrayIndexOutOfBoundsException
没问题。 tt可以看出这个异常是在JDK的哪一部分或者JVM执行的吗?我的意思是 throw new ArrayIndexOutOfBoundsException()
或类似的东西?从调用JNI调用是不可能的?
JVM 抛出 ArrayIndexOutOfBoundsException。字节码不检查数组索引:
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 完成的
首先,请参阅 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
函数。
我想知道 JVM 或 JDK 运行 是如何出现异常的。例如,如果我们有数组
int tab[] = {1, 2, 3};
我们尝试访问
tab[10]
JVM 运行 ArrayIndexOutOfBoundsException
没问题。 tt可以看出这个异常是在JDK的哪一部分或者JVM执行的吗?我的意思是 throw new ArrayIndexOutOfBoundsException()
或类似的东西?从调用JNI调用是不可能的?
JVM 抛出 ArrayIndexOutOfBoundsException。字节码不检查数组索引:
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 完成的
首先,请参阅 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
函数。