8201593: Print array length in ArrayIndexOutOfBoundsException
Reviewed-by: dholmes, mdoerr, smonteith, shade, rriggs
This commit is contained in:
parent
b812ae6e51
commit
ac3043c692
src/hotspot
cpu
aarch64
c1_CodeStubs_aarch64.cppc1_Runtime1_aarch64.cpptemplateInterpreterGenerator_aarch64.cpptemplateTable_aarch64.cpp
arm
ppc
s390
c1_CodeStubs_s390.cppsharedRuntime_s390.cpptemplateInterpreterGenerator_s390.cpptemplateTable_s390.cpp
sparc
c1_CodeStubs_sparc.cppc1_Runtime1_sparc.cppinterp_masm_sparc.cpptemplateInterpreterGenerator_sparc.cpp
x86
share
test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException
@ -48,11 +48,14 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
|
||||
__ 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 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -323,7 +323,7 @@ void Runtime1::initialize_pd() {
|
||||
|
||||
|
||||
// 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 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe
|
||||
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);
|
||||
|
@ -333,16 +333,17 @@ address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
|
||||
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::
|
||||
|
@ -747,6 +747,8 @@ void TemplateTable::index_check(Register array, Register index)
|
||||
}
|
||||
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);
|
||||
|
@ -50,14 +50,18 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
|
||||
|
||||
// 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 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
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 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
#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);
|
||||
|
@ -366,11 +366,15 @@ void Runtime1::initialize_pd() {
|
||||
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);
|
||||
|
||||
|
@ -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 @@ address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
|
||||
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 @@ address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(con
|
||||
__ nop(); // to avoid filling CPU pipeline with invalid instructions
|
||||
__ nop();
|
||||
__ should_not_reach_here();
|
||||
__ bind_literal(Lname);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
@ -872,6 +872,7 @@ void TemplateTable::index_check_without_pop(Register array, Register index) {
|
||||
// convention with generate_ArrayIndexOutOfBounds_handler()
|
||||
__ mov(R4_ArrayIndexOutOfBounds_index, index, hs);
|
||||
}
|
||||
__ mov(R1, array, hs);
|
||||
__ b(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry, hs);
|
||||
}
|
||||
|
||||
|
@ -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 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
__ 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);
|
||||
|
@ -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 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
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;
|
||||
|
||||
|
@ -564,13 +564,13 @@ address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
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();
|
||||
|
@ -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 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, RegisterSet reg
|
||||
__ 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).
|
||||
|
@ -551,9 +551,10 @@ address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
|
||||
|
||||
//
|
||||
// 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 @@ address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(con
|
||||
__ 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;
|
||||
}
|
||||
|
@ -784,7 +784,7 @@ void TemplateTable::index_check(Register array, Register index, unsigned int shi
|
||||
__ 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);
|
||||
|
@ -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 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
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();
|
||||
|
@ -302,7 +302,7 @@ OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address targe
|
||||
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);
|
||||
|
@ -881,27 +881,32 @@ void InterpreterMacroAssembler::index_check_without_pop(Register array, Register
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
@ -255,15 +255,14 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -88,15 +88,17 @@ void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
|
||||
__ 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 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) {
|
||||
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);
|
||||
|
@ -611,26 +611,29 @@ void Runtime1::initialize_pd() {
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
|
@ -102,16 +102,16 @@ address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
|
||||
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::
|
||||
|
@ -757,11 +757,14 @@ void TemplateTable::index_check_without_pop(Register array, Register index) {
|
||||
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
|
||||
|
@ -147,10 +147,14 @@ class RangeCheckStub: public CodeStub {
|
||||
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 @@ class RangeCheckStub: public CodeStub {
|
||||
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"); }
|
||||
|
@ -480,7 +480,7 @@ void LIRGenerator::klass2reg_with_patching(LIR_Opr r, ciMetadata* obj, CodeEmitI
|
||||
|
||||
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::array_range_check(LIR_Opr array, LIR_Opr index,
|
||||
|
||||
|
||||
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 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
|
||||
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 @@ void LIRGenerator::do_NIOCheckIndex(Intrinsic* x) {
|
||||
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 @@ void LIRGenerator::do_LoadIndexed(LoadIndexed* x) {
|
||||
|
||||
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
|
||||
|
@ -641,10 +641,12 @@ address Runtime1::exception_handler_for_pc(JavaThread* thread) {
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
@ -149,7 +149,7 @@ class Runtime1: public AllStatic {
|
||||
|
||||
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);
|
||||
|
@ -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 @@ IRT_ENTRY(void, InterpreterRuntime::create_klass_exception(JavaThread* thread, c
|
||||
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(
|
||||
|
@ -83,7 +83,7 @@ class InterpreterRuntime: AllStatic {
|
||||
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);
|
||||
|
@ -173,11 +173,11 @@ void TemplateInterpreterGenerator::generate_all() {
|
||||
}
|
||||
|
||||
{ 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();
|
||||
}
|
||||
|
||||
|
@ -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 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator {
|
||||
}
|
||||
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);
|
||||
|
@ -251,12 +251,34 @@ void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
|
||||
|
||||
// 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
|
||||
|
@ -138,12 +138,36 @@ void TypeArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos
|
||||
|
||||
// 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 @@ void TypeArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos
|
||||
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_on(outputStream* st) const {
|
||||
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("}");
|
||||
}
|
||||
|
443
test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java
Normal file
443
test/hotspot/jtreg/runtime/exceptionMsgs/ArrayIndexOutOfBoundsException/ArrayIndexOutOfBoundsExceptionTest.java
Normal file
@ -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]");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user