Skip to content

Commit ceff47b

Browse files
robcaslozstefankfisk
committed
8315082: [REDO] Generational ZGC: Tests crash with assert(index == 0 || is_power_of_2(index))
Co-authored-by: Stefan Karlsson <stefank@openjdk.org> Co-authored-by: Erik Österlund <eosterlund@openjdk.org> Reviewed-by: ayang, thartmann, kvn
1 parent df4a25b commit ceff47b

File tree

6 files changed

+178
-31
lines changed

6 files changed

+178
-31
lines changed

src/hotspot/share/gc/shared/c2/barrierSetC2.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,8 +675,15 @@ void BarrierSetC2::clone(GraphKit* kit, Node* src_base, Node* dst_base, Node* si
675675
Node* payload_size = size;
676676
Node* offset = kit->MakeConX(base_off);
677677
payload_size = kit->gvn().transform(new SubXNode(payload_size, offset));
678+
if (is_array) {
679+
// Ensure the array payload size is rounded up to the next BytesPerLong
680+
// multiple when converting to double-words. This is necessary because array
681+
// size does not include object alignment padding, so it might not be a
682+
// multiple of BytesPerLong for sub-long element types.
683+
payload_size = kit->gvn().transform(new AddXNode(payload_size, kit->MakeConX(BytesPerLong - 1)));
684+
}
678685
payload_size = kit->gvn().transform(new URShiftXNode(payload_size, kit->intcon(LogBytesPerLong)));
679-
ArrayCopyNode* ac = ArrayCopyNode::make(kit, false, src_base, offset, dst_base, offset, payload_size, true, false);
686+
ArrayCopyNode* ac = ArrayCopyNode::make(kit, false, src_base, offset, dst_base, offset, payload_size, true, false);
680687
if (is_array) {
681688
ac->set_clone_array();
682689
} else {

src/hotspot/share/opto/arraycopynode.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,13 @@ int ArrayCopyNode::get_count(PhaseGVN *phase) const {
134134
assert (ary_src != nullptr, "not an array or instance?");
135135
// clone passes a length as a rounded number of longs. If we're
136136
// cloning an array we'll do it element by element. If the
137-
// length input to ArrayCopyNode is constant, length of input
138-
// array must be too.
139-
140-
assert((get_length_if_constant(phase) == -1) != ary_src->size()->is_con() ||
137+
// length of the input array is constant, ArrayCopyNode::Length
138+
// must be too. Note that the opposite does not need to hold,
139+
// because different input array lengths (e.g. int arrays with
140+
// 3 or 4 elements) might lead to the same length input
141+
// (e.g. 2 double-words).
142+
assert(!ary_src->size()->is_con() || (get_length_if_constant(phase) >= 0) ||
141143
phase->is_IterGVN() || phase->C->inlining_incrementally() || StressReflectiveCode, "inconsistent");
142-
143144
if (ary_src->size()->is_con()) {
144145
return ary_src->size()->get_con();
145146
}

src/hotspot/share/opto/graphKit.cpp

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3771,7 +3771,10 @@ Node* GraphKit::new_instance(Node* klass_node,
37713771
//-------------------------------new_array-------------------------------------
37723772
// helper for both newarray and anewarray
37733773
// The 'length' parameter is (obviously) the length of the array.
3774-
// See comments on new_instance for the meaning of the other arguments.
3774+
// The optional arguments are for specialized use by intrinsics:
3775+
// - If 'return_size_val', report the non-padded array size (sum of header size
3776+
// and array body) to the caller.
3777+
// - deoptimize_on_exception controls how Java exceptions are handled (rethrow vs deoptimize)
37753778
Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
37763779
Node* length, // number of array elements
37773780
int nargs, // number of arguments to push back for uncommon trap
@@ -3822,25 +3825,21 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
38223825
// The rounding mask is strength-reduced, if possible.
38233826
int round_mask = MinObjAlignmentInBytes - 1;
38243827
Node* header_size = nullptr;
3825-
int header_size_min = arrayOopDesc::base_offset_in_bytes(T_BYTE);
38263828
// (T_BYTE has the weakest alignment and size restrictions...)
38273829
if (layout_is_con) {
38283830
int hsize = Klass::layout_helper_header_size(layout_con);
38293831
int eshift = Klass::layout_helper_log2_element_size(layout_con);
3830-
BasicType etype = Klass::layout_helper_element_type(layout_con);
38313832
if ((round_mask & ~right_n_bits(eshift)) == 0)
38323833
round_mask = 0; // strength-reduce it if it goes away completely
38333834
assert((hsize & right_n_bits(eshift)) == 0, "hsize is pre-rounded");
3835+
int header_size_min = arrayOopDesc::base_offset_in_bytes(T_BYTE);
38343836
assert(header_size_min <= hsize, "generic minimum is smallest");
3835-
header_size_min = hsize;
3836-
header_size = intcon(hsize + round_mask);
3837+
header_size = intcon(hsize);
38373838
} else {
38383839
Node* hss = intcon(Klass::_lh_header_size_shift);
38393840
Node* hsm = intcon(Klass::_lh_header_size_mask);
3840-
Node* hsize = _gvn.transform( new URShiftINode(layout_val, hss) );
3841-
hsize = _gvn.transform( new AndINode(hsize, hsm) );
3842-
Node* mask = intcon(round_mask);
3843-
header_size = _gvn.transform( new AddINode(hsize, mask) );
3841+
header_size = _gvn.transform(new URShiftINode(layout_val, hss));
3842+
header_size = _gvn.transform(new AndINode(header_size, hsm));
38443843
}
38453844

38463845
Node* elem_shift = nullptr;
@@ -3892,25 +3891,30 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
38923891
}
38933892
#endif
38943893

3895-
// Combine header size (plus rounding) and body size. Then round down.
3896-
// This computation cannot overflow, because it is used only in two
3897-
// places, one where the length is sharply limited, and the other
3898-
// after a successful allocation.
3894+
// Combine header size and body size for the array copy part, then align (if
3895+
// necessary) for the allocation part. This computation cannot overflow,
3896+
// because it is used only in two places, one where the length is sharply
3897+
// limited, and the other after a successful allocation.
38993898
Node* abody = lengthx;
3900-
if (elem_shift != nullptr)
3901-
abody = _gvn.transform( new LShiftXNode(lengthx, elem_shift) );
3902-
Node* size = _gvn.transform( new AddXNode(headerx, abody) );
3903-
if (round_mask != 0) {
3904-
Node* mask = MakeConX(~round_mask);
3905-
size = _gvn.transform( new AndXNode(size, mask) );
3899+
if (elem_shift != nullptr) {
3900+
abody = _gvn.transform(new LShiftXNode(lengthx, elem_shift));
39063901
}
3907-
// else if round_mask == 0, the size computation is self-rounding
3902+
Node* non_rounded_size = _gvn.transform(new AddXNode(headerx, abody));
39083903

39093904
if (return_size_val != nullptr) {
39103905
// This is the size
3911-
(*return_size_val) = size;
3906+
(*return_size_val) = non_rounded_size;
39123907
}
39133908

3909+
Node* size = non_rounded_size;
3910+
if (round_mask != 0) {
3911+
Node* mask1 = MakeConX(round_mask);
3912+
size = _gvn.transform(new AddXNode(size, mask1));
3913+
Node* mask2 = MakeConX(~round_mask);
3914+
size = _gvn.transform(new AndXNode(size, mask2));
3915+
}
3916+
// else if round_mask == 0, the size computation is self-rounding
3917+
39143918
// Now generate allocation code
39153919

39163920
// The entire memory state is needed for slow path of the allocation

src/hotspot/share/opto/library_call.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5021,8 +5021,8 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
50215021
PreserveJVMState pjvms(this);
50225022
set_control(array_ctl);
50235023
Node* obj_length = load_array_length(obj);
5024-
Node* obj_size = nullptr;
5025-
Node* alloc_obj = new_array(obj_klass, obj_length, 0, &obj_size, /*deoptimize_on_exception=*/true);
5024+
Node* array_size = nullptr; // Size of the array without object alignment padding.
5025+
Node* alloc_obj = new_array(obj_klass, obj_length, 0, &array_size, /*deoptimize_on_exception=*/true);
50265026

50275027
BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
50285028
if (bs->array_copy_requires_gc_barriers(true, T_OBJECT, true, false, BarrierSetC2::Parsing)) {
@@ -5055,7 +5055,7 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
50555055
// the object.)
50565056

50575057
if (!stopped()) {
5058-
copy_to_clone(obj, alloc_obj, obj_size, true);
5058+
copy_to_clone(obj, alloc_obj, array_size, true);
50595059

50605060
// Present the results of the copy.
50615061
result_reg->init_req(_array_path, control());
@@ -5095,7 +5095,7 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
50955095
if (!stopped()) {
50965096
// It's an instance, and it passed the slow-path tests.
50975097
PreserveJVMState pjvms(this);
5098-
Node* obj_size = nullptr;
5098+
Node* obj_size = nullptr; // Total object size, including object alignment padding.
50995099
// Need to deoptimize on exception from allocation since Object.clone intrinsic
51005100
// is reexecuted if deoptimization occurs and there could be problems when merging
51015101
// exception state between multiple Object.clone versions (reexecute=true vs reexecute=false).
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package compiler.arraycopy;
25+
26+
/**
27+
* @test
28+
* @bug 8315082
29+
* @summary Test that idealization of clone-derived ArrayCopy nodes does not
30+
* trigger assertion failures for different combinations of
31+
* constant/variable array length (in number of elements) and array
32+
* copy length (in words).
33+
* @run main/othervm -Xbatch -XX:-TieredCompilation
34+
* -XX:CompileOnly=compiler.arraycopy.TestCloneArrayWithDifferentLengthConstness::test*
35+
* compiler.arraycopy.TestCloneArrayWithDifferentLengthConstness
36+
*/
37+
38+
public class TestCloneArrayWithDifferentLengthConstness {
39+
40+
public static void main(String[] args) {
41+
for (int i = 0; i < 10_000; i++) {
42+
testConstantArrayLengthAndConstantArrayCopyLength();
43+
}
44+
for (int i = 0; i < 10_000; i++) {
45+
testVariableArrayLengthAndConstantArrayCopyLength(i % 2 == 0);
46+
}
47+
for (int i = 0; i < 10_000; i++) {
48+
testVariableArrayLengthAndVariableArrayCopyLength(i % 2 == 0);
49+
}
50+
}
51+
52+
static int[] testConstantArrayLengthAndConstantArrayCopyLength() {
53+
int[] src = new int[3];
54+
return (int[])src.clone();
55+
}
56+
57+
static int[] testVariableArrayLengthAndConstantArrayCopyLength(boolean p) {
58+
int[] src = new int[p ? 3 : 4];
59+
return (int[])src.clone();
60+
}
61+
62+
static int[] testVariableArrayLengthAndVariableArrayCopyLength(boolean p) {
63+
int[] src = new int[p ? 3 : 42];
64+
return (int[])src.clone();
65+
}
66+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package compiler.gcbarriers;
24+
25+
import java.util.Arrays;
26+
27+
/**
28+
* @test
29+
* @bug 8312749
30+
* @summary Test that, when using a larger object alignment, ZGC arraycopy
31+
* barriers are only applied to actual OOPs, and not to object
32+
* alignment padding words.
33+
* @requires vm.gc.ZGenerational
34+
* @run main/othervm -Xbatch -XX:-TieredCompilation
35+
* -XX:CompileOnly=compiler.gcbarriers.TestArrayCopyWithLargeObjectAlignment::*
36+
* -XX:ObjectAlignmentInBytes=16
37+
* -XX:+UseZGC -XX:+ZGenerational
38+
* compiler.gcbarriers.TestArrayCopyWithLargeObjectAlignment
39+
*/
40+
41+
public class TestArrayCopyWithLargeObjectAlignment {
42+
43+
static Object[] doCopyOf(Object[] array) {
44+
return Arrays.copyOf(array, array.length);
45+
}
46+
47+
static Object[] doClone(Object[] array) {
48+
return array.clone();
49+
}
50+
51+
public static void main(String[] args) {
52+
for (int i = 0; i < 10_000; i++) {
53+
// This test allocates an array 'a', copies it into a new array 'b'
54+
// using Arrays.copyOf, and clones 'b' into yet another array. For
55+
// ObjectAlignmentInBytes=16, the intrinsic implementation of
56+
// Arrays.copyOf leaves the object alignment padding word "b[1]"
57+
// untouched, preserving the badHeapWordVal value '0xbaadbabe'. The
58+
// test checks that this padding word is not processed as a valid
59+
// OOP by the ZGC arraycopy stub underlying the intrinsic
60+
// implementation of Object.clone. Allocating b using the intrinsic
61+
// implementation of Arrays.copyOf is key to reproducing the issue
62+
// because, unlike regular (fast or slow) array allocation,
63+
// Arrays.copyOf does not zero-clear the padding word.
64+
Object[] a = {new Object()};
65+
Object[] b = doCopyOf(a);
66+
doClone(b);
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)