changeset 50643:2f79462aab9b

8201593: Print array length in ArrayIndexOutOfBoundsException. Reviewed-by: dholmes, mdoerr, smonteith, shade, rriggs
author goetz
date Mon, 07 May 2018 09:11:21 +0200
parents 55153a374d18
children bf2f27b92064
files src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp src/hotspot/cpu/aarch64/templateTable_aarch64.cpp src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp src/hotspot/cpu/arm/c1_Runtime1_arm.cpp src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp src/hotspot/cpu/arm/templateTable_arm.cpp src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp src/hotspot/cpu/s390/sharedRuntime_s390.cpp src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp src/hotspot/cpu/s390/templateTable_s390.cpp src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp src/hotspot/cpu/sparc/interp_masm_sparc.cpp src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp src/hotspot/cpu/x86/c1_Runtime1_x86.cpp src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp src/hotspot/cpu/x86/templateTable_x86.cpp src/hotspot/share/c1/c1_CodeStubs.hpp src/hotspot/share/c1/c1_LIRGenerator.cpp src/hotspot/share/c1/c1_Runtime1.cpp src/hotspot/share/c1/c1_Runtime1.hpp src/hotspot/share/interpreter/interpreterRuntime.cpp src/hotspot/share/interpreter/interpreterRuntime.hpp src/hotspot/share/interpreter/templateInterpreterGenerator.cpp src/hotspot/share/interpreter/templateInterpreterGenerator.hpp src/hotspot/share/oops/objArrayKlass.cpp src/hotspot/share/oops/typeArrayKlass.cpp test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java
diffstat 34 files changed, 675 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- 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]");
+        }
+    }
+}