8201593: Print array length in ArrayIndexOutOfBoundsException.
Reviewed-by: dholmes, mdoerr, smonteith, shade, rriggs
--- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp Mon May 07 09:11:21 2018 +0200
@@ -48,11 +48,14 @@
__ 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(false), _index(index), _array(array) {
+ assert(info != NULL, "must have info");
+ _info = new CodeEmitInfo(info);
+}
+
+RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index)
+ : _throw_index_out_of_bounds_exception(true), _index(index), _array(NULL) {
assert(info != NULL, "must have info");
_info = new CodeEmitInfo(info);
}
@@ -69,14 +72,16 @@
}
if (_index->is_cpu_register()) {
- __ mov(rscratch1, _index->as_register());
+ __ mov(r22, _index->as_register());
} else {
- __ mov(rscratch1, _index->as_jint());
+ __ mov(r22, _index->as_jint());
}
Runtime1::StubID stub_id;
if (_throw_index_out_of_bounds_exception) {
stub_id = Runtime1::throw_index_exception_id;
} else {
+ assert(_array != NULL, "sanity");
+ __ mov(r23, _array->as_pointer_register());
stub_id = Runtime1::throw_range_check_failed_id;
}
__ far_call(RuntimeAddress(Runtime1::entry_for(stub_id)), NULL, rscratch2);
--- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp Mon May 07 09:11:21 2018 +0200
@@ -323,7 +323,7 @@
// target: the entry point of the method that creates and posts the exception oop
-// has_argument: true if the exception needs an argument (passed in rscratch1)
+// has_argument: true if the exception needs arguments (passed in r22 and r23)
OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) {
// make a frame and preserve the caller's caller-save registers
@@ -332,7 +332,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, r22, r23);
}
OopMapSet* oop_maps = new OopMapSet();
oop_maps->add_gc_map(call_offset, oop_map);
--- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp Mon May 07 09:11:21 2018 +0200
@@ -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::
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Mon May 07 09:11:21 2018 +0200
@@ -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);
--- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp Mon May 07 09:11:21 2018 +0200
@@ -50,14 +50,18 @@
// 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)
-{
- _info = info == NULL ? NULL : new CodeEmitInfo(info);
+
+RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array)
+ : _throw_index_out_of_bounds_exception(false), _index(index), _array(array) {
+ assert(info != NULL, "must have info");
+ _info = new CodeEmitInfo(info);
}
+RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index)
+ : _throw_index_out_of_bounds_exception(true), _index(index), _array(NULL) {
+ assert(info != NULL, "must have info");
+ _info = new CodeEmitInfo(info);
+}
void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
@@ -73,7 +77,7 @@
return;
}
// Pass the array index on stack because all registers must be preserved
- ce->verify_reserved_argument_area_size(1);
+ ce->verify_reserved_argument_area_size(_throw_index_out_of_bounds_exception ? 1 : 2);
if (_index->is_cpu_register()) {
__ str_32(_index->as_register(), Address(SP));
} else {
@@ -87,6 +91,7 @@
#endif
__ call(Runtime1::entry_for(Runtime1::throw_index_exception_id), relocInfo::runtime_call_type);
} else {
+ __ str(_array->as_pointer_register(), Address(SP, BytesPerWord)); // ??? Correct offset? Correct instruction?
__ call(Runtime1::entry_for(Runtime1::throw_range_check_failed_id), relocInfo::runtime_call_type);
}
ce->add_call_info_here(_info);
--- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp Mon May 07 09:11:21 2018 +0200
@@ -366,11 +366,15 @@
OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) {
OopMap* oop_map = save_live_registers(sasm);
+ int call_offset;
if (has_argument) {
__ ldr(R1, Address(SP, arg1_offset));
+ __ ldr(R2, Address(SP, arg2_offset));
+ call_offset = __ call_RT(noreg, noreg, target, R1, R2);
+ } else {
+ call_offset = __ call_RT(noreg, noreg, target);
}
- int call_offset = __ call_RT(noreg, noreg, target);
OopMapSet* oop_maps = new OopMapSet();
oop_maps->add_gc_map(call_offset, oop_map);
--- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp Mon May 07 09:11:21 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. 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
@@ -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);
@@ -204,7 +202,6 @@
__ nop(); // to avoid filling CPU pipeline with invalid instructions
__ nop();
__ should_not_reach_here();
- __ bind_literal(Lname);
return entry;
}
--- a/src/hotspot/cpu/arm/templateTable_arm.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/arm/templateTable_arm.cpp Mon May 07 09:11:21 2018 +0200
@@ -872,6 +872,7 @@
// convention with generate_ArrayIndexOutOfBounds_handler()
__ mov(R4_ArrayIndexOutOfBounds_index, index, hs);
}
+ __ mov(R1, array, hs);
__ b(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry, hs);
}
--- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp Mon May 07 09:11:21 2018 +0200
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -37,10 +37,14 @@
#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(false), _index(index), _array(array) {
+ assert(info != NULL, "must have info");
+ _info = new CodeEmitInfo(info);
+}
+
+RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index)
+ : _throw_index_out_of_bounds_exception(true), _index(index), _array(NULL) {
assert(info != NULL, "must have info");
_info = new CodeEmitInfo(info);
}
@@ -68,12 +72,16 @@
__ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
__ mtctr(R0);
- Register index = R0; // pass in R0
+ Register index = R0;
if (_index->is_register()) {
__ extsw(index, _index->as_register());
} else {
__ load_const_optimized(index, _index->as_jint());
}
+ if (_array) {
+ __ std(_array->as_pointer_register(), -8, R1_SP);
+ }
+ __ std(index, -16, R1_SP);
__ bctrl();
ce->add_call_info_here(_info);
--- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp Mon May 07 09:11:21 2018 +0200
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -502,8 +502,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;
--- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp Mon May 07 09:11:21 2018 +0200
@@ -564,13 +564,13 @@
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);
+ // R4_ARG2 already contains the array.
// 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;
}
--- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp Mon May 07 09:11:21 2018 +0200
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -39,10 +39,14 @@
#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(false), _index(index), _array(array) {
+ assert(info != NULL, "must have info");
+ _info = new CodeEmitInfo(info);
+}
+
+RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index)
+ : _throw_index_out_of_bounds_exception(true), _index(index), _array(NULL) {
assert(info != NULL, "must have info");
_info = new CodeEmitInfo(info);
}
@@ -71,6 +75,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();
--- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp Mon May 07 09:11:21 2018 +0200
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -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).
--- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp Mon May 07 09:11:21 2018 +0200
@@ -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;
}
--- a/src/hotspot/cpu/s390/templateTable_s390.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/s390/templateTable_s390.cpp Mon May 07 09:11:21 2018 +0200
@@ -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);
--- a/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp Mon May 07 09:11:21 2018 +0200
@@ -35,15 +35,17 @@
#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(false), _index(index), _array(array) {
assert(info != NULL, "must have info");
_info = new CodeEmitInfo(info);
}
+RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index)
+ : _throw_index_out_of_bounds_exception(true), _index(index), _array(NULL) {
+ assert(info != NULL, "must have info");
+ _info = new CodeEmitInfo(info);
+}
void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
@@ -66,6 +68,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();
--- a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp Mon May 07 09:11:21 2018 +0200
@@ -302,7 +302,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);
--- a/src/hotspot/cpu/sparc/interp_masm_sparc.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/sparc/interp_masm_sparc.cpp Mon May 07 09:11:21 2018 +0200
@@ -881,27 +881,32 @@
assert_not_delayed();
verify_oop(array);
- // sign extend since tos (index) can be a 32bit value
+ // Sign extend since tos (index) can be a 32bit value.
sra(index, G0, index);
- // check array
+ // Check array.
Label ptr_ok;
tst(array);
- throw_if_not_1_x( notZero, ptr_ok );
- delayed()->ld( array, arrayOopDesc::length_offset_in_bytes(), tmp ); // check index
- throw_if_not_2( Interpreter::_throw_NullPointerException_entry, G3_scratch, ptr_ok);
+ throw_if_not_1_x(notZero, ptr_ok);
+ delayed()->ld(array, arrayOopDesc::length_offset_in_bytes(), tmp); // Check index.
+ throw_if_not_2(Interpreter::_throw_NullPointerException_entry, G3_scratch, ptr_ok);
Label index_ok;
cmp(index, tmp);
- 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
- // convention: move aberrant index into G3_scratch for exception message
- mov(index, G3_scratch);
- throw_if_not_2( Interpreter::_throw_ArrayIndexOutOfBoundsException_entry, G4_scratch, index_ok);
+ 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 Otos_i for exception message.
+ 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
- if (index_shift > 0) add(array, index, res); // addr - const offset in index
+ if (index_shift > 0) { add(array, index, res); } // addr - const offset in index
}
--- a/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp Mon May 07 09:11:21 2018 +0200
@@ -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;
}
--- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp Mon May 07 09:11:21 2018 +0200
@@ -88,15 +88,17 @@
__ 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(false), _index(index), _array(array) {
assert(info != NULL, "must have info");
_info = new CodeEmitInfo(info);
}
+RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index)
+ : _throw_index_out_of_bounds_exception(true), _index(index), _array(NULL) {
+ assert(info != NULL, "must have info");
+ _info = new CodeEmitInfo(info);
+}
void RangeCheckStub::emit_code(LIR_Assembler* ce) {
__ bind(_entry);
@@ -120,6 +122,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);
--- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp Mon May 07 09:11:21 2018 +0200
@@ -611,26 +611,29 @@
}
-// target: the entry point of the method that creates and posts the exception oop
-// has_argument: true if the exception needs an argument (passed on stack because registers must be preserved)
-
+// Target: the entry point of the method that creates and posts the exception oop.
+// has_argument: true if the exception needs arguments (passed on the stack because
+// registers must be preserved).
OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) {
- // preserve all registers
- int num_rt_args = has_argument ? 2 : 1;
+ // Preserve all registers.
+ 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
- // verify that no old value is used accidentally
+ // Now all registers are saved and can be used freely.
+ // Verify that no old value is used accidentally.
__ invalidate_registers(true, true, true, true, true, true);
- // registers used by this stub
+ // Registers used by this stub.
const Register temp_reg = rbx;
- // load argument for exception that is passed as an argument into the stub
+ // Load arguments for exception that are passed as arguments into the stub.
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
--- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp Mon May 07 09:11:21 2018 +0200
@@ -102,16 +102,16 @@
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
+ // The expression stack must be empty before entering the VM if an
+ // exception happened.
__ empty_expression_stack();
- // setup parameters
- // ??? convention: expect aberrant index in register ebx
+
+ // Setup parameters.
+ // ??? convention: expect aberrant index in register ebx/rbx.
+ // Pass array to create more detailed exceptions.
Register rarg = NOT_LP64(rax) LP64_ONLY(c_rarg1);
- __ lea(rarg, ExternalAddress((address)name));
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/cpu/x86/templateTable_x86.cpp Mon May 07 09:11:21 2018 +0200
@@ -757,11 +757,14 @@
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.
+ __ mov(NOT_LP64(rax) LP64_ONLY(c_rarg1), array);
+ __ jump(ExternalAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry));
+ __ bind(skip);
}
-
void TemplateTable::iaload() {
transition(itos, itos);
// rax: index
--- a/src/hotspot/share/c1/c1_CodeStubs.hpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/c1/c1_CodeStubs.hpp Mon May 07 09:11:21 2018 +0200
@@ -147,10 +147,14 @@
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);
+ // For ArrayIndexOutOfBoundsException.
+ RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array);
+ // For IndexOutOfBoundsException.
+ RangeCheckStub(CodeEmitInfo* info, LIR_Opr index);
virtual void emit_code(LIR_Assembler* e);
virtual CodeEmitInfo* info() const { return _info; }
virtual bool is_exception_throw_stub() const { return true; }
@@ -158,6 +162,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"); }
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp Mon May 07 09:11:21 2018 +0200
@@ -480,7 +480,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);
@@ -494,7 +494,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);
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
@@ -1592,7 +1592,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
@@ -1756,7 +1756,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());
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);
@@ -1837,12 +1837,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
--- a/src/hotspot/share/c1/c1_Runtime1.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/c1/c1_Runtime1.cpp Mon May 07 09:11:21 2018 +0200
@@ -641,10 +641,12 @@
}
-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);
+ const int len = 35;
+ assert(len < strlen("Index %d out of bounds for length %d"), "Must allocate more space for message.");
+ char message[2 * jintAsStringSize + len];
+ 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
--- a/src/hotspot/share/c1/c1_Runtime1.hpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/c1/c1_Runtime1.hpp Mon May 07 09:11:21 2018 +0200
@@ -149,7 +149,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);
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp Mon May 07 09:11:21 2018 +0200
@@ -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(
--- a/src/hotspot/share/interpreter/interpreterRuntime.hpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/interpreter/interpreterRuntime.hpp Mon May 07 09:11:21 2018 +0200
@@ -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);
--- a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp Mon May 07 09:11:21 2018 +0200
@@ -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();
}
--- a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp Mon May 07 09:11:21 2018 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. 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
@@ -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);
--- a/src/hotspot/share/oops/objArrayKlass.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/oops/objArrayKlass.cpp Mon May 07 09:11:21 2018 +0200
@@ -251,12 +251,34 @@
// 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("arraycopy: source index %d out of bounds for object array[%d]",
+ src_pos, s->length());
+ } else if (dst_pos < 0) {
+ ss.print("arraycopy: destination index %d out of bounds for object array[%d]",
+ dst_pos, d->length());
+ } else {
+ ss.print("arraycopy: length %d is negative", 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());
+ if ((((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) ||
+ (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length())) {
+ // Pass specific exception reason.
+ ResourceMark rm;
+ stringStream ss;
+ if (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) {
+ ss.print("arraycopy: last source index %u out of bounds for object array[%d]",
+ (unsigned int) length + (unsigned int) src_pos, s->length());
+ } else {
+ ss.print("arraycopy: last destination index %u out of bounds for object array[%d]",
+ (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
--- a/src/hotspot/share/oops/typeArrayKlass.cpp Sat May 12 17:22:56 2018 +0530
+++ b/src/hotspot/share/oops/typeArrayKlass.cpp Mon May 07 09:11:21 2018 +0200
@@ -138,12 +138,36 @@
// 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("arraycopy: source index %d out of bounds for %s[%d]",
+ src_pos, type2name_tab[ArrayKlass::cast(s->klass())->element_type()], s->length());
+ } else if (dst_pos < 0) {
+ ss.print("arraycopy: destination index %d out of bounds for %s[%d]",
+ dst_pos, type2name_tab[ArrayKlass::cast(d->klass())->element_type()], d->length());
+ } else {
+ ss.print("arraycopy: length %d is negative", 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());
+ if ((((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) ||
+ (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length())) {
+ // Pass specific exception reason.
+ ResourceMark rm;
+ stringStream ss;
+ if (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) {
+ ss.print("arraycopy: last source index %u out of bounds for %s[%d]",
+ (unsigned int) length + (unsigned int) src_pos,
+ type2name_tab[ArrayKlass::cast(s->klass())->element_type()], s->length());
+ } else {
+ ss.print("arraycopy: last destination index %u out of bounds for %s[%d]",
+ (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 +181,6 @@
HeapAccess<ARRAYCOPY_ATOMIC>::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 +263,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("}");
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java Mon May 07 09:11:21 2018 +0200
@@ -0,0 +1,443 @@
+/*
+ * 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. 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
+ */
+
+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 of the ArrayIndexOutOfBoundsException.
+ */
+public class ArrayIndexOutOfBoundsExceptionTest {
+
+ // Some fields used in the test.
+ static int[] staticArray = new int[0];
+ static long[][] staticLongArray = new long[0][0];
+ ArrayList<String> names = new ArrayList<>();
+ ArrayList<String> curr;
+
+ public static void main(String[] args) {
+ ArrayIndexOutOfBoundsExceptionTest t = new ArrayIndexOutOfBoundsExceptionTest();
+ try {
+ t.testAIOOBMessages();
+ } catch (Exception e) {}
+ }
+
+ /**
+ *
+ */
+ 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 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(),
+ "arraycopy: source index -17 out of bounds for object array[10]");
+ }
+
+ try {
+ System.arraycopy(oa1, 2, oa2, -18, 5);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: destination index -18 out of bounds for object array[5]");
+ }
+
+ try {
+ System.arraycopy(oa1, 2, oa2, 0, -19);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: length -19 is negative");
+ }
+
+ try {
+ System.arraycopy(oa1, 8, oa2, 0, 5);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: last source index 13 out of bounds for object array[10]");
+ }
+
+ try {
+ System.arraycopy(oa1, 1, oa2, 0, 7);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: last destination index 7 out of bounds for object array[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(),
+ "arraycopy: source index -17 out of bounds for double[10]");
+ }
+
+ try {
+ System.arraycopy(da2, 2, da3, -18, 5);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: destination index -18 out of bounds for double[5]");
+ }
+
+ try {
+ System.arraycopy(da2, 2, da3, 0, -19);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: length -19 is negative");
+ }
+
+ try {
+ System.arraycopy(da2, 8, da3, 0, 5);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: last source index 13 out of bounds for double[10]");
+ }
+
+ try {
+ System.arraycopy(da2, 1, da3, 0, 7);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: last destination index 7 out of bounds for double[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(),
+ "arraycopy: source index -17 out of bounds for boolean[10]");
+ }
+
+ try {
+ System.arraycopy(ba2, 2, ba3, -18, 5);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: destination index -18 out of bounds for byte[5]");
+ }
+
+ try {
+ System.arraycopy(sa2, 2, sa3, 0, -19);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: length -19 is negative");
+ }
+
+ try {
+ System.arraycopy(ca2, 8, ca3, 0, 5);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: last source index 13 out of bounds for char[10]");
+ }
+
+ try {
+ System.arraycopy(ia2, 2, ia3, 0, -19);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: length -19 is negative");
+ }
+
+ try {
+ System.arraycopy(la2, 1, la3, 0, 7);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: last destination index 7 out of bounds for long[5]");
+ }
+
+ try {
+ System.arraycopy(fa2, 1, fa3, 0, 7);
+ fail();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertEquals(e.getMessage(),
+ "arraycopy: last destination index 7 out of bounds for float[5]");
+ }
+ }
+}