diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index efbf900f3d7..88a395feb64 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4327,12 +4327,16 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { length = _gvn.transform(new SubINode(end, start)); } - // Bail out if length is negative. + // Bail out if length is negative (i.e., if start > end). // Without this the new_array would throw // NegativeArraySizeException but IllegalArgumentException is what // should be thrown generate_negative_guard(length, bailout, &length); + // Bail out if start is larger than the original length + Node* orig_tail = _gvn.transform(new SubINode(orig_length, start)); + generate_negative_guard(orig_tail, bailout, &orig_tail); + if (bailout->req() > 1) { PreserveJVMState pjvms(this); set_control(_gvn.transform(bailout)); @@ -4342,8 +4346,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { if (!stopped()) { // How many elements will we copy from the original? - // The answer is MinI(orig_length - start, length). - Node* orig_tail = _gvn.transform(new SubINode(orig_length, start)); + // The answer is MinI(orig_tail, length). Node* moved = generate_min_max(vmIntrinsics::_min, orig_tail, length); // Generate a direct call to the right arraycopy function(s). @@ -4391,7 +4394,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) { if (!stopped()) { newcopy = new_array(klass_node, length, 0); // no arguments to push - ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, true, false, + ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, true, true, load_object_klass(original), klass_node); if (!is_copyOfRange) { ac->set_copyof(validated); diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index 1c658f20715..9600a3c6c25 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -1266,7 +1266,7 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) { generate_arraycopy(ac, alloc, &ctrl, merge_mem, &io, adr_type, T_OBJECT, src, src_offset, dest, dest_offset, length, - true, !ac->is_copyofrange()); + true, ac->has_negative_length_guard()); return; } diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyOfRangeGuards.java b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyOfRangeGuards.java new file mode 100644 index 00000000000..e5886d7002b --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyOfRangeGuards.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024, 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 + * 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 + * @bug 8323682 + * @summary Test that the appropriate guards are generated for the copyOfRange + * intrinsic, even if the result of the array copy is not used. + * + * @run main/othervm -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.arraycopy.TestArrayCopyOfRangeGuards::test + * -Xbatch + * compiler.arraycopy.TestArrayCopyOfRangeGuards + */ + +package compiler.arraycopy; + +import java.util.Arrays; + +public class TestArrayCopyOfRangeGuards { + static int counter = 0; + + public static void main(String[] args) { + Object[] array = new Object[10]; + for (int i = 0; i < 50_000; i++) { + test(array); + } + if (counter != 50_000) { + throw new RuntimeException("Test failed"); + } + } + + static void test(Object[] array) { + try { + Arrays.copyOfRange(array, 15, 20, Object[].class); + } catch (ArrayIndexOutOfBoundsException e) { + // Expected + counter++; + } + } +}