# HG changeset patch # User goetz # Date 1523884640 -7200 # Mon Apr 16 15:17:20 2018 +0200 # Node ID ddee06468d4e915e16146a1efa0cec74c2ea561a # Parent ad1a5f49b8aef93a24e1a725be9837b63a1aa11f 8201593: Print array length in ArrayIndexOutOfBoundsException. diff --git a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp --- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp @@ -51,11 +51,8 @@ __ b(_continuation); } -RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, - bool throw_index_out_of_bounds_exception) - : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception) - , _index(index) -{ +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array) + : _throw_index_out_of_bounds_exception(array == NULL), _index(index), _array(array) { assert(info != NULL, "must have info"); _info = new CodeEmitInfo(info); } @@ -78,6 +75,8 @@ } Runtime1::StubID stub_id; if (_throw_index_out_of_bounds_exception) { + assert(_array != NULL, "sanity"); + __ mov(rscratch2, _array->as_pointer_register()); stub_id = Runtime1::throw_index_exception_id; } else { stub_id = Runtime1::throw_range_check_failed_id; diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -356,7 +356,7 @@ if (GenerateRangeChecks && needs_range_check) { if (use_length) { __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result(), array.result())); } else { array_range_check(array.result(), index.result(), null_check_info, range_check_info); // range_check also does the null check diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -336,7 +336,7 @@ if (!has_argument) { call_offset = __ call_RT(noreg, noreg, target); } else { - call_offset = __ call_RT(noreg, noreg, target, rscratch1); + call_offset = __ call_RT(noreg, noreg, target, rscratch1, rscratch2); } OopMapSet* oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, oop_map); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -333,16 +333,17 @@ return entry; } -address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler( - const char* name) { +address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() { address entry = __ pc(); // expression stack must be empty before entering the VM if an // exception happened __ empty_expression_stack(); // setup parameters + // ??? convention: expect aberrant index in register r1 __ movw(c_rarg2, r1); - __ mov(c_rarg1, (address)name); + // ??? convention: expect array in register r3 + __ mov(c_rarg1, r3); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime:: diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -747,6 +747,8 @@ } Label ok; __ br(Assembler::LO, ok); + // ??? convention: move array into r3 for exception message + __ mov(r3, array); __ mov(rscratch1, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); __ br(rscratch1); __ bind(ok); diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp --- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp +++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp @@ -53,11 +53,8 @@ // TODO: ARM - is it possible to inline these stubs into the main code stream? -RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, - bool throw_index_out_of_bounds_exception) - : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception) - , _index(index) -{ +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array) + : _throw_index_out_of_bounds_exception(array == NULL), _index(index), _array(array) { _info = info == NULL ? NULL : new CodeEmitInfo(info); } @@ -83,6 +80,8 @@ __ mov_slow(Rtemp, _index->as_jint()); // Rtemp should be OK in C1 __ str_32(Rtemp, Address(SP)); } + __ mov_slow(Rtemp, _array->as_pointer_register()); + __ str(Rtemp, Address(SP, BytesPerWord)); // ??? Correct offset? Correct instruction? if (_throw_index_out_of_bounds_exception) { #ifdef AARCH64 diff --git a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp --- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp @@ -591,7 +591,7 @@ if (GenerateRangeChecks && needs_range_check) { if (use_length) { __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result(), array.result())); } else { array_range_check(array.result(), index.result(), null_check_info, range_check_info); // range_check also does the null check diff --git a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp --- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp +++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp @@ -366,6 +366,7 @@ if (has_argument) { __ ldr(R1, Address(SP, arg1_offset)); + __ ldr(R2, Address(SP, arg2_offset)); } int call_offset = __ call_RT(noreg, noreg, target); diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -185,18 +185,16 @@ return entry; } -address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) { +address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() { address entry = __ pc(); // index is in R4_ArrayIndexOutOfBounds_index - InlinedString Lname(name); - // expression stack must be empty before entering the VM if an exception happened __ empty_expression_stack(); // setup parameters - __ ldr_literal(R1, Lname); + // Array expected in R1. __ mov(R2, R4_ArrayIndexOutOfBounds_index); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), R1, R2); diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -793,6 +793,7 @@ // convention with generate_ArrayIndexOutOfBounds_handler() __ mov(R4_ArrayIndexOutOfBounds_index, index, hs); } + __ mov(R1, array, hs); __ b(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry, hs); } diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -40,10 +40,8 @@ #define __ ce->masm()-> -RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, - bool throw_index_out_of_bounds_exception) - : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception) - , _index(index) { +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array) + : _throw_index_out_of_bounds_exception(array == NULL), _index(index), _array(array) { assert(info != NULL, "must have info"); _info = new CodeEmitInfo(info); } @@ -77,6 +75,10 @@ } else { __ load_const_optimized(index, _index->as_jint()); } + if (_array) { + __ std(_array->as_pointer_register(), -8, R1_SP); + } + __ std(R0, -16, R1_SP); __ bctrl(); ce->add_call_info_here(_info); diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -364,7 +364,7 @@ if (GenerateRangeChecks && needs_range_check) { if (use_length) { __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result(), array.result())); } else { array_range_check(array.result(), index.result(), null_check_info, range_check_info); // Range_check also does the null check. diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -507,8 +507,7 @@ case throw_range_check_failed_id: { __ set_info("range_check_failed", dont_gc_arguments); // Arguments will be discarded. - __ std(R0, -8, R1_SP); // Pass index on stack. - oop_maps = generate_exception_throw_with_stack_parms(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), 1); + oop_maps = generate_exception_throw_with_stack_parms(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), 2); } break; diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -564,13 +564,12 @@ return entry; } -address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) { +address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() { address entry = __ pc(); __ empty_expression_stack(); - __ load_const_optimized(R4_ARG2, (address) name); // Index is in R17_tos. __ mr(R5_ARG3, R17_tos); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException)); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), R4_ARG2, R5_ARG3); return entry; } diff --git a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp --- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp +++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp @@ -42,10 +42,8 @@ #undef CHECK_BAILOUT #define CHECK_BAILOUT() { if (ce->compilation()->bailed_out()) return; } -RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, - bool throw_index_out_of_bounds_exception) : - _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception), - _index(index) { +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array) : + _throw_index_out_of_bounds_exception(array == NULL), _index(index), _array(array) { assert(info != NULL, "must have info"); _info = new CodeEmitInfo(info); } @@ -74,6 +72,7 @@ stub_id = Runtime1::throw_index_exception_id; } else { stub_id = Runtime1::throw_range_check_failed_id; + __ lgr_if_needed(Z_R0_scratch, _array->as_pointer_register()); } ce->emit_call_c(Runtime1::entry_for (stub_id)); CHECK_BAILOUT(); diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp --- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp @@ -302,7 +302,7 @@ if (GenerateRangeChecks && needs_range_check) { if (use_length) { __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result(), array.result())); } else { array_range_check(array.result(), index.result(), null_check_info, range_check_info); // Range_check also does the null check. diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -314,8 +314,8 @@ __ save_return_pc(return_pc); // Push a new frame (includes stack linkage). - // use return_pc as scratch for push_frame. Z_R0_scratch (the default) and Z_R1_scratch are - // illegally used to pass parameters (SAPJVM extension) by RangeCheckStub::emit_code(). + // Use return_pc as scratch for push_frame. Z_R0_scratch (the default) and Z_R1_scratch are + // illegally used to pass parameters by RangeCheckStub::emit_code(). __ push_frame(frame_size_in_bytes, return_pc); // We have to restore return_pc right away. // Nobody else will. Furthermore, return_pc isn't necessarily the default (Z_R14). diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -551,9 +551,10 @@ // // Args: +// Z_ARG2: oop of array // Z_ARG3: aberrant index // -address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char * name) { +address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() { address entry = __ pc(); address excp = CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException); @@ -562,8 +563,7 @@ __ empty_expression_stack(); // Setup parameters. - // Leave out the name and use register for array to create more detailed exceptions. - __ load_absolute_address(Z_ARG2, (address) name); + // Pass register with array to create more detailed exceptions. __ call_VM(noreg, excp, Z_ARG2, Z_ARG3); return entry; } diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -784,7 +784,7 @@ __ z_cl(index, Address(array, arrayOopDesc::length_offset_in_bytes())); __ z_brl(index_ok); __ lgr_if_needed(Z_ARG3, index); // See generate_ArrayIndexOutOfBounds_handler(). - // Give back the array to create more detailed exceptions. + // Pass the array to create more detailed exceptions. __ lgr_if_needed(Z_ARG2, array); // See generate_ArrayIndexOutOfBounds_handler(). __ load_absolute_address(Z_R1_scratch, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); diff --git a/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp b/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp --- a/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp +++ b/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp @@ -38,11 +38,8 @@ #define __ ce->masm()-> -RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, - bool throw_index_out_of_bounds_exception) - : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception) - , _index(index) -{ +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array) + : _throw_index_out_of_bounds_exception(array == NULL), _index(index), _array(array) { assert(info != NULL, "must have info"); _info = new CodeEmitInfo(info); } @@ -69,6 +66,7 @@ if (_throw_index_out_of_bounds_exception) { __ call(Runtime1::entry_for(Runtime1::throw_index_exception_id), relocInfo::runtime_call_type); } else { + __ mov(_array->as_pointer_register(), G5); __ call(Runtime1::entry_for(Runtime1::throw_range_check_failed_id), relocInfo::runtime_call_type); } __ delayed()->nop(); diff --git a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp --- a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp +++ b/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp @@ -360,7 +360,7 @@ if (GenerateRangeChecks && needs_range_check) { if (use_length) { __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result(), array.result())); } else { array_range_check(array.result(), index.result(), null_check_info, range_check_info); // range_check also does the null check diff --git a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp b/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp --- a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp +++ b/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp @@ -289,7 +289,7 @@ if (!has_argument) { call_offset = __ call_RT(noreg, noreg, target); } else { - call_offset = __ call_RT(noreg, noreg, target, G4); + call_offset = __ call_RT(noreg, noreg, target, G4, G5); } OopMapSet* oop_maps = new OopMapSet(); oop_maps->add_gc_map(call_offset, oop_map); diff --git a/src/hotspot/cpu/sparc/interp_masm_sparc.cpp b/src/hotspot/cpu/sparc/interp_masm_sparc.cpp --- a/src/hotspot/cpu/sparc/interp_masm_sparc.cpp +++ b/src/hotspot/cpu/sparc/interp_masm_sparc.cpp @@ -894,8 +894,10 @@ throw_if_not_1_icc( lessUnsigned, index_ok ); if (index_shift > 0) delayed()->sll(index, index_shift, index); else delayed()->add(array, index, res); // addr - const offset in index + // Pass the array to create more detailed exceptions. // convention: move aberrant index into G3_scratch for exception message - mov(index, G3_scratch); + mov(index, Otos_i); + mov(array, G3_scratch); throw_if_not_2( Interpreter::_throw_ArrayIndexOutOfBoundsException_entry, G4_scratch, index_ok); // add offset if didn't do it in delay slot diff --git a/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp b/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp --- a/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp +++ b/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp @@ -255,15 +255,14 @@ } -address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) { +address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() { address entry = __ pc(); // expression stack must be empty before entering the VM if an exception happened __ empty_expression_stack(); + // Pass the array to create more detailed exceptions. // convention: expect aberrant index in register G3_scratch, then shuffle the // index to G4_scratch for the VM call - __ mov(G3_scratch, G4_scratch); - __ set((intptr_t)name, G3_scratch); - __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), G3_scratch, G4_scratch); + __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), G3_scratch, Otos_i); __ should_not_reach_here(); return entry; } diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp --- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp @@ -91,10 +91,8 @@ __ jmp(_continuation); } -RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, - bool throw_index_out_of_bounds_exception) - : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception) - , _index(index) +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array) + : _throw_index_out_of_bounds_exception(array == NULL), _index(index), _array(array) { assert(info != NULL, "must have info"); _info = new CodeEmitInfo(info); @@ -123,6 +121,7 @@ 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))); ce->add_call_info_here(_info); diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -303,7 +303,7 @@ if (GenerateRangeChecks && needs_range_check) { if (use_length) { __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result(), array.result())); } else { array_range_check(array.result(), index.result(), null_check_info, range_check_info); // range_check also does the null check diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -605,7 +605,7 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) { // preserve all registers - int num_rt_args = has_argument ? 2 : 1; + int num_rt_args = has_argument ? (2 + 1) : 1; OopMap* oop_map = save_live_registers(sasm, num_rt_args); // now all registers are saved and can be used freely @@ -619,7 +619,10 @@ if (has_argument) { #ifdef _LP64 __ movptr(c_rarg1, Address(rbp, 2*BytesPerWord)); + __ movptr(c_rarg2, Address(rbp, 3*BytesPerWord)); #else + __ movptr(temp_reg, Address(rbp, 3*BytesPerWord)); + __ push(temp_reg); __ movptr(temp_reg, Address(rbp, 2*BytesPerWord)); __ push(temp_reg); #endif // _LP64 diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -102,8 +102,7 @@ return entry; } -address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler( - const char* name) { +address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() { address entry = __ pc(); // expression stack must be empty before entering the VM if an // exception happened @@ -111,7 +110,7 @@ // setup parameters // ??? convention: expect aberrant index in register ebx Register rarg = NOT_LP64(rax) LP64_ONLY(c_rarg1); - __ lea(rarg, ExternalAddress((address)name)); + // Pass array to create more detailed exceptions. __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime:: diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -757,8 +757,16 @@ assert(rbx != array, "different registers"); __ movl(rbx, index); } - __ jump_cc(Assembler::aboveEqual, - ExternalAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry)); + Label skip; + __ jccb(Assembler::below, skip); + // Pass array to create more detailed exceptions. +#ifdef IA32 + __ mov(rax, array); +#else // AMD64 + __ mov(c_rarg1, array); +#endif + __ jump(ExternalAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry)); + __ bind(skip); } diff --git a/src/hotspot/share/c1/c1_CodeStubs.hpp b/src/hotspot/share/c1/c1_CodeStubs.hpp --- a/src/hotspot/share/c1/c1_CodeStubs.hpp +++ b/src/hotspot/share/c1/c1_CodeStubs.hpp @@ -147,10 +147,11 @@ private: CodeEmitInfo* _info; LIR_Opr _index; + LIR_Opr _array; bool _throw_index_out_of_bounds_exception; public: - RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, bool throw_index_out_of_bounds_exception = false); + RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array); virtual void emit_code(LIR_Assembler* e); virtual CodeEmitInfo* info() const { return _info; } virtual bool is_exception_throw_stub() const { return true; } @@ -158,6 +159,7 @@ virtual void visit(LIR_OpVisitState* visitor) { visitor->do_slow_case(_info); visitor->do_input(_index); + if (_array) { visitor->do_input(_array); } } #ifndef PRODUCT virtual void print_name(outputStream* out) const { out->print("RangeCheckStub"); } diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -490,7 +490,7 @@ 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); + 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); @@ -504,7 +504,7 @@ void LIRGenerator::nio_range_check(LIR_Opr buffer, LIR_Opr index, LIR_Opr result, CodeEmitInfo* info) { - CodeStub* stub = new RangeCheckStub(info, index, true); + CodeStub* stub = new RangeCheckStub(info, index, NULL); if (index->is_constant()) { cmp_mem_int(lir_cond_belowEqual, buffer, java_nio_Buffer::limit_offset(), index->as_jint(), info); __ branch(lir_cond_belowEqual, T_INT, stub); // forward branch @@ -1889,7 +1889,7 @@ LIR_Opr result = rlock_result(x); if (GenerateRangeChecks) { CodeEmitInfo* info = state_for(x); - CodeStub* stub = new RangeCheckStub(info, index.result(), true); + CodeStub* stub = new RangeCheckStub(info, index.result(), NULL); if (index.result()->is_constant()) { cmp_mem_int(lir_cond_belowEqual, buf.result(), java_nio_Buffer::limit_offset(), index.result()->as_jint(), info); __ branch(lir_cond_belowEqual, T_INT, stub); @@ -1973,12 +1973,12 @@ if (GenerateRangeChecks && needs_range_check) { if (StressLoopInvariantCodeMotion && range_check_info->deoptimize_on_exception()) { - __ branch(lir_cond_always, T_ILLEGAL, new RangeCheckStub(range_check_info, index.result())); + __ branch(lir_cond_always, T_ILLEGAL, new RangeCheckStub(range_check_info, index.result(), array.result())); } else if (use_length) { // TODO: use a (modified) version of array_range_check that does not require a // constant length to be loaded to a register __ cmp(lir_cond_belowEqual, length.result(), index.result()); - __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result(), array.result())); } else { array_range_check(array.result(), index.result(), null_check_info, range_check_info); // The range check performs the null check, so clear it out for the load diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -627,10 +627,10 @@ } -JRT_ENTRY(void, Runtime1::throw_range_check_exception(JavaThread* thread, int index)) +JRT_ENTRY(void, Runtime1::throw_range_check_exception(JavaThread* thread, int index, arrayOopDesc* a)) NOT_PRODUCT(_throw_range_check_exception_count++;) - char message[jintAsStringSize]; - sprintf(message, "%d", index); + char message[2 * jintAsStringSize + strlen("Index %d out-of-bounds for length %d.")]; + sprintf(message, "Index %d out-of-bounds for length %d.", index, a->length()); SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message); JRT_END diff --git a/src/hotspot/share/c1/c1_Runtime1.hpp b/src/hotspot/share/c1/c1_Runtime1.hpp --- a/src/hotspot/share/c1/c1_Runtime1.hpp +++ b/src/hotspot/share/c1/c1_Runtime1.hpp @@ -143,7 +143,7 @@ static address exception_handler_for_pc(JavaThread* thread); - static void throw_range_check_exception(JavaThread* thread, int index); + static void throw_range_check_exception(JavaThread* thread, int index, arrayOopDesc* a); static void throw_index_exception(JavaThread* thread, int index); static void throw_div0_exception(JavaThread* thread); static void throw_null_pointer_exception(JavaThread* thread); diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -58,6 +58,7 @@ #include "runtime/icache.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" +#include "runtime/javaCalls.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/osThread.hpp" #include "runtime/sharedRuntime.hpp" @@ -446,17 +447,16 @@ thread->set_vm_result(exception()); IRT_END - -IRT_ENTRY(void, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException(JavaThread* thread, char* name, jint index)) - char message[jintAsStringSize]; - // lookup exception klass - TempNewSymbol s = SymbolTable::new_symbol(name, CHECK); +IRT_ENTRY(void, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException(JavaThread* thread, arrayOopDesc* a, jint index)) if (ProfileTraps) { note_trap(thread, Deoptimization::Reason_range_check, CHECK); } - // create exception - sprintf(message, "%d", index); - THROW_MSG(s, message); + + ResourceMark rm(thread); + stringStream ss; + ss.print("Index %d out-of-bounds for length %d.", index, a->length()); + + THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); IRT_END IRT_ENTRY(void, InterpreterRuntime::throw_ClassCastException( diff --git a/src/hotspot/share/interpreter/interpreterRuntime.hpp b/src/hotspot/share/interpreter/interpreterRuntime.hpp --- a/src/hotspot/share/interpreter/interpreterRuntime.hpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp @@ -83,7 +83,7 @@ Klass* interfaceKlass); static void throw_StackOverflowError(JavaThread* thread); static void throw_delayed_StackOverflowError(JavaThread* thread); - static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, char* name, jint index); + static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, arrayOopDesc* a, jint index); static void throw_ClassCastException(JavaThread* thread, oopDesc* obj); static void create_exception(JavaThread* thread, char* name, char* message); static void create_klass_exception(JavaThread* thread, char* name, oopDesc* obj); diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp @@ -173,11 +173,11 @@ } { CodeletMark cm(_masm, "throw exception entrypoints"); - Interpreter::_throw_ArrayIndexOutOfBoundsException_entry = generate_ArrayIndexOutOfBounds_handler("java/lang/ArrayIndexOutOfBoundsException"); - Interpreter::_throw_ArrayStoreException_entry = generate_klass_exception_handler("java/lang/ArrayStoreException" ); - Interpreter::_throw_ArithmeticException_entry = generate_exception_handler("java/lang/ArithmeticException" , "/ by zero"); + Interpreter::_throw_ArrayIndexOutOfBoundsException_entry = generate_ArrayIndexOutOfBounds_handler(); + Interpreter::_throw_ArrayStoreException_entry = generate_klass_exception_handler("java/lang/ArrayStoreException"); + Interpreter::_throw_ArithmeticException_entry = generate_exception_handler("java/lang/ArithmeticException", "/ by zero"); Interpreter::_throw_ClassCastException_entry = generate_ClassCastException_handler(); - Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException" , NULL ); + Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException", NULL); Interpreter::_throw_StackOverflowError_entry = generate_StackOverflowError_handler(); } diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp @@ -51,7 +51,7 @@ } address generate_exception_handler_common(const char* name, const char* message, bool pass_oop); address generate_ClassCastException_handler(); - address generate_ArrayIndexOutOfBounds_handler(const char* name); + address generate_ArrayIndexOutOfBounds_handler(); address generate_return_entry_for(TosState state, int step, size_t index_size); address generate_earlyret_entry_for(TosState state); address generate_deopt_entry_for(TosState state, int step, address continuation = NULL); diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -251,12 +251,31 @@ // Check is all offsets and lengths are non negative if (src_pos < 0 || dst_pos < 0 || length < 0) { - THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + // Pass specific exception reason. + ResourceMark rm; + stringStream ss; + if (src_pos < 0) { + ss.print("while trying to copy from index %i of an object array with length %i", src_pos, s->length()); + } else if (dst_pos < 0) { + ss.print("while trying to copy to index %i of an object array with length %i", dst_pos, d->length()); + } else { + ss.print("while trying to copy a negative range %i from an object array with length %i to an object array with length %i", + length, s->length(), d->length()); + } + THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); } // Check if the ranges are valid if ( (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) || (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length()) ) { - THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + // Pass specific exception reason. + ResourceMark rm; + stringStream ss; + if (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) { + ss.print("while trying to copy from index %u of an object array with length %i", (unsigned int) length + (unsigned int) src_pos, s->length()); + } else { + ss.print("while trying to copy to index %u of an object array with length %i", (unsigned int) length + (unsigned int) dst_pos, d->length()); + } + THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); } // Special case. Boundary cases must be checked first diff --git a/src/hotspot/share/oops/typeArrayKlass.cpp b/src/hotspot/share/oops/typeArrayKlass.cpp --- a/src/hotspot/share/oops/typeArrayKlass.cpp +++ b/src/hotspot/share/oops/typeArrayKlass.cpp @@ -138,12 +138,38 @@ // Check is all offsets and lengths are non negative if (src_pos < 0 || dst_pos < 0 || length < 0) { - THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + // Pass specific exception reason. + ResourceMark rm; + stringStream ss; + if (src_pos < 0) { + ss.print("while trying to copy from index %i of a %s array with length %i", + src_pos, type2name_tab[ArrayKlass::cast(s->klass())->element_type()], s->length()); + } else if (dst_pos < 0) { + ss.print("while trying to copy to index %i of a %s array with length %i", + dst_pos, type2name_tab[ArrayKlass::cast(d->klass())->element_type()], d->length()); + } else { + ss.print("while trying to copy a negative range %i from a %s array with length %i to a %s array with length %i", + length, type2name_tab[ArrayKlass::cast(s->klass())->element_type()], s->length(), + type2name_tab[ArrayKlass::cast(d->klass())->element_type()], d->length()); + } + THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); } // Check if the ranges are valid if ( (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) || (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length()) ) { - THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + // Pass specific exception reason. + ResourceMark rm; + stringStream ss; + if (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) { + ss.print("while trying to copy from index %u of a %s array with length %i", + (unsigned int) length + (unsigned int) src_pos, + type2name_tab[ArrayKlass::cast(s->klass())->element_type()], s->length()); + } else { + ss.print("while trying to copy to index %u of a %s array with length %i", + (unsigned int) length + (unsigned int) dst_pos, + type2name_tab[ArrayKlass::cast(d->klass())->element_type()], d->length()); + } + THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); } // Check zero copy if (length == 0) @@ -157,7 +183,6 @@ HeapAccess::arraycopy(s, d, src, dst, (size_t)length << l2es); } - // create a klass of array holding typeArrays Klass* TypeArrayKlass::array_klass_impl(bool or_null, int n, TRAPS) { int dim = dimension(); @@ -240,16 +265,11 @@ void TypeArrayKlass::print_value_on(outputStream* st) const { assert(is_klass(), "must be klass"); st->print("{type array "); - switch (element_type()) { - case T_BOOLEAN: st->print("bool"); break; - case T_CHAR: st->print("char"); break; - case T_FLOAT: st->print("float"); break; - case T_DOUBLE: st->print("double"); break; - case T_BYTE: st->print("byte"); break; - case T_SHORT: st->print("short"); break; - case T_INT: st->print("int"); break; - case T_LONG: st->print("long"); break; - default: ShouldNotReachHere(); + BasicType bt = element_type(); + if (bt == T_BOOLEAN) { + st->print("bool"); + } else { + st->print("%s", type2name_tab[bt]); } st->print("}"); } diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java new file mode 100644 --- /dev/null +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java @@ -0,0 +1,920 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Test extended ArrayIndexOutOfBoundsException message for + * class files generated without debug information. The message lists + * information about the array and the indexes involved. + * @compile ArrayIndexOutOfBoundsExceptionTest.java + * @run testng ArrayIndexOutOfBoundsExceptionTest + * @run testng/othervm -Xcomp -XX:-TieredCompilation ArrayIndexOutOfBoundsExceptionTest + * @run testng/othervm -Xcomp -XX:TieredStopAtLevel=1 ArrayIndexOutOfBoundsExceptionTest + * @author Ann-Kathrin Wasle + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +/** + * Tests the detailed messages for the ArrayIndexOutOfBoundsException. + */ +public class ArrayIndexOutOfBoundsExceptionTest { + + // Some fields used in the test. + static int[] staticArray = new int[0]; + static long[][] staticLongArray = new long[0][0]; + DoubleArrayGen dag; + ArrayList names = new ArrayList<>(); + ArrayList curr; + + public static void main(String[] args) { + ArrayIndexOutOfBoundsExceptionTest t = new ArrayIndexOutOfBoundsExceptionTest(); + try { + t.testCreationViaNew(); + t.testCreationViaReflection(); + t.testCreationViaSerialization(); + t.testLoadedFromLocalVariable1(); + t.testLoadedFromLocalVariable2(); + t.testLoadedFromLocalVariable3(); + t.testLoadedFromLocalVariable4(); + t.testLoadedFromLocalVariable5(); + t.testLoadedFromLocalVariable6(); + t.testLoadedFromLocalVariable7(); + t.testLoadedFromLocalVariable8(); + t.testLoadedFromLocalVariable9(); + t.testLoadedFromLocalVariable10(); + t.testLoadedFromLocalVariable11(); + t.testLoadedFromMethod1(); + t.testLoadedFromMethod2(); + t.testLoadedFromMethod3(); + t.testLoadedFromMethod4(); + t.testLoadedFromStaticField1(); + t.testLoadedFromStaticField2(); + t.testLoadedFromStaticField3(); + t.testLoadedFromStaticField4(); + t.testWorkWithCompiler(); + t.testMissingLocalVariableTable(); + t.testAIOOBMessages(); + } catch (Exception e) {} + } + + /** + * + */ + @Test + public void testCreationViaNew() { + assertNull(new ArrayIndexOutOfBoundsException().getMessage()); + } + + /** + * @throws Exception + */ + @Test + public void testCreationViaReflection() throws Exception { + Exception ex = ArrayIndexOutOfBoundsException.class.newInstance(); + assertNull(ex.getMessage()); + } + + /** + * @throws Exception + */ + @Test + public void testCreationViaSerialization() throws Exception { + Object o = new ArrayIndexOutOfBoundsException(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(o); + ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bis); + Exception ex = (Exception) ois.readObject(); + assertNull(ex.getMessage()); + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable1() { + Object[] a = new Object[5]; + + try { + a[10].hashCode(); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable2() { + Object[] a = new Object[7]; + + try { + a[-7] = null; + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable3() { + byte[] a = new byte[0]; + + try { + assertTrue(a[99] == 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable4() { + char[] a = new char[0]; + + try { + a[0] = 0; + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable5() { + double[] a = new double[0]; + + try { + assertTrue(a[0] == 0); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable6() { + float[] a = new float[0]; + + try { + a[0] = 0; + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable7() { + int[] a = new int[0]; + + try { + assertTrue(a[0] == 0); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable8() { + long[] a = new long[0]; + + try { + a[0] = 0; + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable9() { + short[] a = new short[5]; + + try { + assertTrue(a[10] == 0); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable10() { + int[][][] a = new int[1][0][0]; + + try { + assertTrue(a[0][1][2] == 0); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromLocalVariable11() { + int[][][] a = new int[1][0][0]; + + try { + a[0][1][2] = 0; + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromMethod1() { + + try { + assertTrue((ArrayGenerator.arrayReturner(false))[0] == null); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromMethod2() { + try { + assertTrue( + ((new ArrayGenerator().returnMyArray(1, 1, (short) 1)))[0] == null); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromMethod3() { + try { + assertTrue((returnArray(null, null, 1f))[0] == null); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromMethod4() { + ImplTestLoadedFromMethod4(new DoubleArrayGenImpl()); + } + + /** + * @param gen + */ + public void ImplTestLoadedFromMethod4(DoubleArrayGen gen) { + try { + (gen.getArray())[0] = 1.0; + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromStaticField1() { + try { + assertTrue(staticArray[0] == 1); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromStaticField2() { + try { + staticArray[0] = 2; + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromStaticField3() { + try { + assertTrue(staticLongArray[0][0] == 1L); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testLoadedFromStaticField4() { + try { + staticLongArray[0][0] = 2L; + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testWorkWithCompiler() { + int[] a = {0, 1, 2}; + int i1 = 2; + int i2 = 3; + + for (int i = 0; i < 10000000; i++) { // One 0 less is enough for d64. + testImplWorkWithCompiler(a, i1); + } + testImplWorkWithCompiler(a, i2); + } + + /** + * @param a + * @param i + */ + public void testImplWorkWithCompiler(int[] a, int i) { + try { + assertTrue(a[i] == 2); + } catch (ArrayIndexOutOfBoundsException e) { + e.printStackTrace(); + assertNotNull(e.getMessage()); + } + } + + private Object[] returnArray(String[][] dummy1, int[][][] dummy2, float dummy3) { + return new Object[0]; + } + + /** + * + */ + public static interface DoubleArrayGen { + /** + * @return double Array + */ + public double[] getArray(); + } + + /** + * + */ + public static class DoubleArrayGenImpl implements DoubleArrayGen { + @Override + public double[] getArray() { + return new double[0]; + } + } + + /** + * + */ + public static class ArrayGenerator { + + /** + * @param dummy1 + * @return Object Array + */ + public static Object[] arrayReturner(boolean dummy1) { + return new Object[0]; + } + + /** + * @param dummy1 + * @param dummy2 + * @param dummy3 + * @return Object Array + */ + public Object[] returnMyArray(double dummy1, long dummy2, short dummy3) { + return new Object[0]; + } + } + + + /** + * + */ + @Test + public void testMissingLocalVariableTable() { + doTestMissingLocalVariableTable(names); + + System.out.println("Names"); + + for (int i = 0; i < names.size(); ++i) { + System.out.println(names.get(i)); + } + + String[] expectedNames = new String[] { + "Index 0 out-of-bounds for length 0.", + "Index -1 out-of-bounds for length 10.", + "Index 1 out-of-bounds for length 0.", + "Index 7 out-of-bounds for length 5." + }; + + assertEquals(expectedNames.length, names.size()); + + for (int i = 0; i < expectedNames.length; ++i) { + assertEquals(names.get(i), expectedNames[i]); + } + } + + private void doTestMissingLocalVariableTable(ArrayList names) { + curr = names; + doTestMissingLocalVariableTable1(); + doTestMissingLocalVariableTable2(new Object[10], new boolean[0], new double[5][1]); + } + + private void doTestMissingLocalVariableTable1() { + try { + staticArray[0] = 0; + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + curr.add(e.getMessage()); + } + } + + private void doTestMissingLocalVariableTable2(Object[] o1, boolean z1[], double[][] dd1) { + try { + o1[-1].hashCode(); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + curr.add(e.getMessage()); + } + + try { + z1[1] = true; + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + curr.add(e.getMessage()); + } + + try { + assertTrue(dd1[7][1] == 0); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + curr.add(e.getMessage()); + } + } + + /** + * + */ + @Test + public void testAIOOBMessages() { + boolean[] za1 = new boolean[0]; + byte[] ba1 = new byte[0]; + short[] sa1 = new short[0]; + char[] ca1 = new char[0]; + int[] ia1 = new int[0]; + long[] la1 = new long[0]; + float[] fa1 = new float[0]; + double[] da1 = new double[0]; + Object[] oa1 = new Object[10]; + Object[] oa2 = new Object[5]; + + boolean[] za2 = new boolean[10]; + boolean[] za3 = new boolean[5]; + byte[] ba2 = new byte[10]; + byte[] ba3 = new byte[5]; + short[] sa2 = new short[10]; + short[] sa3 = new short[5]; + char[] ca2 = new char[10]; + char[] ca3 = new char[5]; + int[] ia2 = new int[10]; + int[] ia3 = new int[5]; + long[] la2 = new long[10]; + long[] la3 = new long[5]; + float[] fa2 = new float[10]; + float[] fa3 = new float[5]; + double[] da2 = new double[10]; + double[] da3 = new double[5]; + + try { + System.out.println(za1[-5]); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index -5 out-of-bounds for length 0."); + } + + try { + System.out.println(ba1[0]); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(sa1[0]); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(ca1[0]); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(ia1[0]); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(la1[0]); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(fa1[0]); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(da1[0]); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(oa1[12]); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 12 out-of-bounds for length 10."); + } + + try { + System.out.println(za1[0] = false); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(ba1[0] = 0); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(sa1[0] = 0); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(ca1[0] = 0); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(ia1[0] = 0); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(la1[0] = 0); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(fa1[0] = 0); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(da1[0] = 0); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + try { + System.out.println(oa1[-2] = null); + fail(); + } + catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index -2 out-of-bounds for length 10."); + } + + try { + assertTrue((ArrayGenerator.arrayReturner(false))[0] == null); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + try { + staticArray[0] = 2; + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "Index 0 out-of-bounds for length 0."); + } + + // Test all five possible messages of arraycopy exceptions thrown in ObjArrayKlass::copy_array() + + try { + System.arraycopy(oa1, -17, oa2, 0, 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy from index -17 of an object array with length 10"); + } + + try { + System.arraycopy(oa1, 2, oa2, -18, 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy to index -18 of an object array with length 5"); + } + + try { + System.arraycopy(oa1, 2, oa2, 0, -19); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy a negative range -19 from an object array with length 10 to an object array with length 5"); + } + + try { + System.arraycopy(oa1, 8, oa2, 0, 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy from index 13 of an object array with length 10"); + } + + try { + System.arraycopy(oa1, 1, oa2, 0, 7); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy to index 7 of an object array with length 5"); + } + + // Test all five possible messages of arraycopy exceptions thrown in TypeArrayKlass::copy_array() + + try { + System.arraycopy(da2, -17, da3, 0, 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy from index -17 of a double array with length 10"); + } + + try { + System.arraycopy(da2, 2, da3, -18, 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy to index -18 of a double array with length 5"); + } + + try { + System.arraycopy(da2, 2, da3, 0, -19); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy a negative range -19 from a double array with length 10 to a double array with length 5"); + } + + try { + System.arraycopy(da2, 8, da3, 0, 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy from index 13 of a double array with length 10"); + } + + try { + System.arraycopy(da2, 1, da3, 0, 7); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy to index 7 of a double array with length 5"); + } + + // Test all possible basic types in the messages of arraycopy exceptions thrown in TypeArrayKlass::copy_array() + + try { + System.arraycopy(za2, -17, za3, 0, 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy from index -17 of a boolean array with length 10"); + } + + try { + System.arraycopy(ba2, 2, ba3, -18, 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy to index -18 of a byte array with length 5"); + } + + try { + System.arraycopy(sa2, 2, sa3, 0, -19); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy a negative range -19 from a short array with length 10 to a short array with length 5"); + } + + try { + System.arraycopy(ca2, 8, ca3, 0, 5); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy from index 13 of a char array with length 10"); + } + + try { + System.arraycopy(ia2, 2, ia3, 0, -19); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy a negative range -19 from a int array with length 10 to a int array with length 5"); + } + + try { + System.arraycopy(la2, 1, la3, 0, 7); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy to index 7 of a long array with length 5"); + } + + try { + System.arraycopy(fa2, 1, fa3, 0, 7); + fail(); + } catch (ArrayIndexOutOfBoundsException e) { + assertEquals(e.getMessage(), + "while trying to copy to index 7 of a float array with length 5"); + } + } +}