Skip to content

Commit 6b43939

Browse files
committed
8359270: C2: alignment check should consider base offset when emitting arraycopy runtime call
Reviewed-by: thartmann, kvn
1 parent 81985d4 commit 6b43939

File tree

3 files changed

+136
-8
lines changed

3 files changed

+136
-8
lines changed

src/hotspot/share/opto/library_call.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,9 +1575,14 @@ bool LibraryCallKit::inline_string_toBytesU() {
15751575
Node* src_start = array_element_address(value, offset, T_CHAR);
15761576
Node* dst_start = basic_plus_adr(newcopy, arrayOopDesc::base_offset_in_bytes(T_BYTE));
15771577

1578-
// Check if src array address is aligned to HeapWordSize (dst is always aligned)
1579-
const TypeInt* toffset = gvn().type(offset)->is_int();
1580-
bool aligned = toffset->is_con() && ((toffset->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
1578+
// Check if dst array address is aligned to HeapWordSize
1579+
bool aligned = (arrayOopDesc::base_offset_in_bytes(T_BYTE) % HeapWordSize == 0);
1580+
// If true, then check if src array address is aligned to HeapWordSize
1581+
if (aligned) {
1582+
const TypeInt* toffset = gvn().type(offset)->is_int();
1583+
aligned = toffset->is_con() && ((arrayOopDesc::base_offset_in_bytes(T_CHAR) +
1584+
toffset->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
1585+
}
15811586

15821587
// Figure out which arraycopy runtime method to call (disjoint, uninitialized).
15831588
const char* copyfunc_name = "arraycopy";
@@ -1658,8 +1663,8 @@ bool LibraryCallKit::inline_string_getCharsU() {
16581663
// Check if array addresses are aligned to HeapWordSize
16591664
const TypeInt* tsrc = gvn().type(src_begin)->is_int();
16601665
const TypeInt* tdst = gvn().type(dst_begin)->is_int();
1661-
bool aligned = tsrc->is_con() && ((tsrc->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0) &&
1662-
tdst->is_con() && ((tdst->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
1666+
bool aligned = tsrc->is_con() && ((arrayOopDesc::base_offset_in_bytes(T_BYTE) + tsrc->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0) &&
1667+
tdst->is_con() && ((arrayOopDesc::base_offset_in_bytes(T_CHAR) + tdst->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
16631668

16641669
// Figure out which arraycopy runtime method to call (disjoint, uninitialized).
16651670
const char* copyfunc_name = "arraycopy";

src/hotspot/share/opto/stringopts.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,9 +1473,14 @@ void PhaseStringOpts::arraycopy(GraphKit& kit, IdealKit& ideal, Node* src_array,
14731473

14741474
Node* src_ptr = __ array_element_address(src_array, __ intcon(0), T_BYTE);
14751475
Node* dst_ptr = __ array_element_address(dst_array, start, T_BYTE);
1476-
// Check if destination address is aligned to HeapWordSize
1477-
const TypeInt* tdst = __ gvn().type(start)->is_int();
1478-
bool aligned = tdst->is_con() && ((tdst->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0);
1476+
// Check if src array address is aligned to HeapWordSize
1477+
bool aligned = (arrayOopDesc::base_offset_in_bytes(T_BYTE) % HeapWordSize == 0);
1478+
// If true, then check if dst array address is aligned to HeapWordSize
1479+
if (aligned) {
1480+
const TypeInt* tdst = __ gvn().type(start)->is_int();
1481+
aligned = tdst->is_con() && ((arrayOopDesc::base_offset_in_bytes(T_BYTE) +
1482+
tdst->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0);
1483+
}
14791484
// Figure out which arraycopy runtime method to call (disjoint, uninitialized).
14801485
const char* copyfunc_name = "arraycopy";
14811486
address copyfunc_addr = StubRoutines::select_arraycopy_function(elembt, aligned, true, copyfunc_name, true);
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Copyright (c) 2025, Institute of Software, Chinese Academy of Sciences.
3+
* All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation.
9+
*
10+
* This code is distributed in the hope that it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
* version 2 for more details (a copy is included in the LICENSE file that
14+
* accompanied this code).
15+
*
16+
* You should have received a copy of the GNU General Public License version
17+
* 2 along with this work; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*
20+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21+
* or visit www.oracle.com if you need additional information or have any
22+
* questions.
23+
*/
24+
25+
package compiler.c2.irTests.stringopts;
26+
27+
import compiler.lib.ir_framework.*;
28+
29+
/**
30+
* @test
31+
* @bug 8359270
32+
* @requires vm.debug == true & vm.compiler2.enabled
33+
* @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="riscv64" | os.arch=="aarch64"
34+
* @summary C2: alignment check should consider base offset when emitting arraycopy runtime call.
35+
* @library /test/lib /
36+
* @run driver compiler.c2.irTests.stringopts.TestArrayCopySelect
37+
*/
38+
39+
public class TestArrayCopySelect {
40+
41+
public static final String input_strU = "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28";
42+
public static final char[] input_arrU = new char[] {'\u0f21', '\u0f22', '\u0f23', '\u0f24',
43+
'\u0f25', '\u0f26', '\u0f27', '\u0f28'};
44+
45+
public static String output_strU;
46+
public static char[] output_arrU;
47+
48+
public static void main(String[] args) {
49+
TestFramework.runWithFlags("-XX:-UseCompactObjectHeaders",
50+
"-XX:-CompactStrings",
51+
"-XX:CompileCommand=inline,java.lang.StringBuilder::toString",
52+
"-XX:CompileCommand=inline,java.lang.StringUTF16::getChars",
53+
"-XX:CompileCommand=inline,java.lang.StringUTF16::toBytes");
54+
55+
TestFramework.runWithFlags("-XX:+UseCompactObjectHeaders",
56+
"-XX:-CompactStrings",
57+
"-XX:CompileCommand=inline,java.lang.StringBuilder::toString",
58+
"-XX:CompileCommand=inline,java.lang.StringUTF16::getChars",
59+
"-XX:CompileCommand=inline,java.lang.StringUTF16::toBytes");
60+
}
61+
62+
@Test
63+
@Warmup(10000)
64+
@IR(applyIf = {"UseCompactObjectHeaders", "false"},
65+
counts = {IRNode.CALL_OF, "arrayof_jshort_disjoint_arraycopy", ">0"})
66+
static void testSBToStringAligned() {
67+
// Exercise the StringBuilder.toString API
68+
StringBuilder sb = new StringBuilder(input_strU);
69+
output_strU = sb.append(input_strU).toString();
70+
}
71+
72+
@Test
73+
@Warmup(10000)
74+
@IR(applyIf = {"UseCompactObjectHeaders", "true"},
75+
counts = {IRNode.CALL_OF, "arrayof_jshort_disjoint_arraycopy", "0"})
76+
static void testSBToStringUnAligned() {
77+
// Exercise the StringBuilder.toString API
78+
StringBuilder sb = new StringBuilder(input_strU);
79+
output_strU = sb.append(input_strU).toString();
80+
}
81+
82+
@Test
83+
@Warmup(10000)
84+
@IR(applyIf = {"UseCompactObjectHeaders", "false"},
85+
counts = {IRNode.CALL_OF, "arrayof_jshort_disjoint_arraycopy", ">0"})
86+
static void testStrUGetCharsAligned() {
87+
// Exercise the StringUTF16.getChars API
88+
output_arrU = input_strU.toCharArray();
89+
}
90+
91+
@Test
92+
@Warmup(10000)
93+
@IR(applyIf = {"UseCompactObjectHeaders", "true"},
94+
counts = {IRNode.CALL_OF, "arrayof_jshort_disjoint_arraycopy", "0"})
95+
static void testStrUGetCharsUnAligned() {
96+
// Exercise the StringUTF16.getChars API
97+
output_arrU = input_strU.toCharArray();
98+
}
99+
100+
@Test
101+
@Warmup(10000)
102+
@IR(applyIf = {"UseCompactObjectHeaders", "false"},
103+
counts = {IRNode.CALL_OF, "arrayof_jshort_disjoint_arraycopy", ">0"})
104+
static void testStrUtoBytesAligned() {
105+
// Exercise the StringUTF16.toBytes API
106+
output_strU = String.valueOf(input_arrU);
107+
}
108+
109+
@Test
110+
@Warmup(10000)
111+
@IR(applyIf = {"UseCompactObjectHeaders", "true"},
112+
counts = {IRNode.CALL_OF, "arrayof_jshort_disjoint_arraycopy", "0"})
113+
static void testStrUtoBytesUnAligned() {
114+
// Exercise the StringUTF16.toBytes API
115+
output_strU = String.valueOf(input_arrU);
116+
}
117+
118+
}

0 commit comments

Comments
 (0)