Переводчик.Реализация 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)));
Наконец, это приводит к вызову функции Exceptions::_throw
в коде JVM C ++.