Skip to content

Commit e8c6ab2

Browse files
author
Boris Ulasevich
committed
cleanup. remove dummy code. add test.
1 parent 61b3ae6 commit e8c6ab2

7 files changed

Lines changed: 162 additions & 74 deletions

File tree

src/hotspot/share/code/aotCodeCache.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2038,7 +2038,6 @@ void AOTCodeAddressTable::init_extrs() {
20382038
ADD_EXTERNAL_ADDRESS(OptoRuntime::new_instance_C);
20392039
ADD_EXTERNAL_ADDRESS(OptoRuntime::new_array_C);
20402040
ADD_EXTERNAL_ADDRESS(OptoRuntime::new_array_nozero_C);
2041-
ADD_EXTERNAL_ADDRESS(OptoRuntime::multianewarray2_C);
20422041
ADD_EXTERNAL_ADDRESS(OptoRuntime::multianewarray3_C);
20432042
ADD_EXTERNAL_ADDRESS(OptoRuntime::multianewarray4_C);
20442043
ADD_EXTERNAL_ADDRESS(OptoRuntime::multianewarray5_C);

src/hotspot/share/opto/parse.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ class Parse : public GraphKit {
549549
void do_anewarray();
550550
void do_multianewarray();
551551
Node* expand_multianewarray(ciArrayKlass* array_klass, Node* *lengths, int ndimensions, int nargs);
552-
void init_array2d(Node* array, ciArrayKlass* array_klass, Node* length1, Node* length2);
552+
Node* multianewarray2(ciArrayKlass* array_klass, Node* length1, Node* length2);
553553

554554
// implementation of jsr/ret
555555
void do_jsr();

src/hotspot/share/opto/parse3.cpp

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -327,45 +327,48 @@ Node* Parse::expand_multianewarray(ciArrayKlass* array_klass, Node* *lengths, in
327327
/**
328328
* Initialize the graph, equivalent to the following Java code:
329329
*
330-
* for (int index = 0; index < length1; index++)
331-
* multi_array[index] = new array_klass[length2];
332-
*
333-
* The actual loop structure:
334-
*
335-
* if (length1 > 0) {
336-
* int index = 0;
337-
* do {
338-
* multi_array[index] = new T[length2];
339-
* index++;
340-
* } while (index < length1);
341-
* }
342-
*
343-
* The corresponding C2 IR graph:
344-
*
345-
* CmpI(length1, 0) -> Bool(gt) -> If
346-
* IfFalse => skip_ctrl
347-
* IfTrue =>
348-
* CastII(length2, POS) -> length2
349-
* LoopNode(IfTrue, back_edge)
350-
* Phi(LoopNode, 0, next_index) -> index
351-
* Phi(LoopNode, pre_mem, body_mem)
352-
* Phi(LoopNode, pre_io, body_io)
353-
* AllocateArray(klass_1, length2) -> array
354-
* StoreP(array_element_address(multi_array, index), array)
355-
* AddI(index, 1) -> next_index
356-
* CmpI(next_index, length1) -> Bool(lt) -> If
357-
* IfTrue => back_edge => LoopNode
358-
* IfFalse => loop_exit
359-
* Region(skip_ctrl, loop_exit)
360-
* Phi(Region, pre_mem, body_mem)
361-
* Phi(Region, pre_io, body_io)
330+
* multi_array = new T[length1][];
331+
* for (int index = 0; index < length1; index++) {
332+
* multi_array[index] = new array_klass[length2];
333+
* }
362334
*/
363-
void Parse::init_array2d(Node* multi_array,
364-
ciArrayKlass* array_klass,
365-
Node* length1, Node* length2) {
335+
Node* Parse::multianewarray2(ciArrayKlass* array_klass, Node* length1, Node* length2) {
336+
337+
assert(length1 != nullptr && length2 != nullptr, "");
338+
Node* multi_array = new_array(makecon(TypeKlassPtr::make(array_klass, Type::trust_interfaces)), length1, false);
366339

367340
C->set_has_loops(true);
368341

342+
// The actual loop structure:
343+
//
344+
// if (length1 > 0) {
345+
// int index = 0;
346+
// do {
347+
// multi_array[index] = new T[length2];
348+
// index++;
349+
// } while (index < length1);
350+
// }
351+
//
352+
// The corresponding C2 IR graph:
353+
//
354+
// CmpI(length1, 0) -> Bool(gt) -> If
355+
// IfFalse => skip_ctrl
356+
// IfTrue =>
357+
// CastII(length2, POS) -> length2
358+
// LoopNode(IfTrue, back_edge)
359+
// Phi(LoopNode, 0, next_index) -> index
360+
// Phi(LoopNode, pre_mem, body_mem)
361+
// Phi(LoopNode, pre_io, body_io)
362+
// AllocateArray(klass_1, length2) -> array
363+
// StoreP(array_element_address(multi_array, index), array)
364+
// AddI(index, 1) -> next_index
365+
// CmpI(next_index, length1) -> Bool(lt) -> If
366+
// IfTrue => back_edge => LoopNode
367+
// IfFalse => loop_exit
368+
// Region(skip_ctrl, loop_exit)
369+
// Phi(Region, pre_mem, body_mem)
370+
// Phi(Region, pre_io, body_io)
371+
369372
Node* i_init = _gvn.intcon(0);
370373
Node* cmp_init = _gvn.transform(new CmpINode(length1, i_init));
371374
Node* bool_init = _gvn.transform(new BoolNode(cmp_init, BoolTest::gt));
@@ -408,10 +411,11 @@ void Parse::init_array2d(Node* multi_array,
408411

409412
Node* array = _gvn.transform(new_array(klass_node, length2, false));
410413

411-
store_to_memory(control(),
414+
const TypeOopPtr* elemtype = _gvn.type(multi_array)->is_aryptr()->elem()->make_oopptr();
415+
access_store_at(multi_array,
412416
array_element_address(multi_array, index, T_OBJECT),
413-
array,
414-
T_OBJECT, MemNode::unordered, TypeAryPtr::OOPS, false, false, true);
417+
TypeAryPtr::OOPS,
418+
array, elemtype, T_OBJECT, IN_HEAP | IS_ARRAY);
415419

416420
Node* new_i = _gvn.transform(new AddINode(index, _gvn.intcon(1)));
417421
Node* cmp = _gvn.transform(new CmpINode(new_i, length1));
@@ -444,6 +448,8 @@ void Parse::init_array2d(Node* multi_array,
444448
set_control(exit_region);
445449
set_all_memory(exit_mem);
446450
set_i_o(exit_io);
451+
452+
return multi_array;
447453
}
448454

449455
void Parse::do_multianewarray() {
@@ -507,12 +513,7 @@ void Parse::do_multianewarray() {
507513
Node* obj = nullptr;
508514
{ PreserveReexecuteState preexecs(this);
509515
inc_sp(ndimensions);
510-
511-
Node* length1 = length[0];
512-
Node* length2 = length[1];
513-
assert(length1 != nullptr && length2 != nullptr, "");
514-
obj = new_array(makecon(TypeKlassPtr::make(array_klass, Type::trust_interfaces)), length1, false);
515-
init_array2d(obj, array_klass, length1, length2);
516+
obj = multianewarray2(array_klass, length[0], length[1]);
516517
}
517518
push(obj);
518519
return;
@@ -521,7 +522,7 @@ void Parse::do_multianewarray() {
521522
address fun = nullptr;
522523
switch (ndimensions) {
523524
case 1: ShouldNotReachHere(); break;
524-
case 2: fun = OptoRuntime::multianewarray2_Java(); break;
525+
case 2: ShouldNotReachHere(); break;
525526
case 3: fun = OptoRuntime::multianewarray3_Java(); break;
526527
case 4: fun = OptoRuntime::multianewarray4_Java(); break;
527528
case 5: fun = OptoRuntime::multianewarray5_Java(); break;

src/hotspot/share/opto/runtime.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ bool OptoRuntime::generate(ciEnv* env) {
172172

173173
const TypeFunc* OptoRuntime::_new_instance_Type = nullptr;
174174
const TypeFunc* OptoRuntime::_new_array_Type = nullptr;
175-
const TypeFunc* OptoRuntime::_multianewarray2_Type = nullptr;
176175
const TypeFunc* OptoRuntime::_multianewarray3_Type = nullptr;
177176
const TypeFunc* OptoRuntime::_multianewarray4_Type = nullptr;
178177
const TypeFunc* OptoRuntime::_multianewarray5_Type = nullptr;
@@ -426,22 +425,6 @@ JRT_END
426425

427426
// Note: multianewarray for one dimension is handled inline by GraphKit::new_array.
428427

429-
// multianewarray for 2 dimensions
430-
JRT_ENTRY(void, OptoRuntime::multianewarray2_C(Klass* elem_type, int len1, int len2, JavaThread* current))
431-
#ifndef PRODUCT
432-
SharedRuntime::_multi2_ctr++; // multianewarray for 1 dimension
433-
#endif
434-
assert(check_compiled_frame(current), "incorrect caller");
435-
assert(elem_type->is_klass(), "not a class");
436-
jint dims[2];
437-
dims[0] = len1;
438-
dims[1] = len2;
439-
Handle holder(current, elem_type->klass_holder()); // keep the klass alive
440-
oop obj = ArrayKlass::cast(elem_type)->multi_allocate(2, dims, THREAD);
441-
deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION);
442-
current->set_vm_result_oop(obj);
443-
JRT_END
444-
445428
// multianewarray for 3 dimensions
446429
JRT_ENTRY(void, OptoRuntime::multianewarray3_C(Klass* elem_type, int len1, int len2, int len3, JavaThread* current))
447430
#ifndef PRODUCT
@@ -2269,7 +2252,6 @@ NamedCounter* OptoRuntime::new_named_counter(JVMState* youngest_jvms, NamedCount
22692252
void OptoRuntime::initialize_types() {
22702253
_new_instance_Type = make_new_instance_Type();
22712254
_new_array_Type = make_new_array_Type();
2272-
_multianewarray2_Type = multianewarray_Type(2);
22732255
_multianewarray3_Type = multianewarray_Type(3);
22742256
_multianewarray4_Type = multianewarray_Type(4);
22752257
_multianewarray5_Type = multianewarray_Type(5);

src/hotspot/share/opto/runtime.hpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ class OptoRuntime : public AllStatic {
125125
// static TypeFunc* data members
126126
static const TypeFunc* _new_instance_Type;
127127
static const TypeFunc* _new_array_Type;
128-
static const TypeFunc* _multianewarray2_Type;
129128
static const TypeFunc* _multianewarray3_Type;
130129
static const TypeFunc* _multianewarray4_Type;
131130
static const TypeFunc* _multianewarray5_Type;
@@ -217,7 +216,6 @@ class OptoRuntime : public AllStatic {
217216

218217
// Allocate storage for a multi-dimensional arrays
219218
// Note: needs to be fixed for arbitrary number of dimensions
220-
static void multianewarray2_C(Klass* klass, int len1, int len2, JavaThread* current);
221219
static void multianewarray3_C(Klass* klass, int len1, int len2, int len3, JavaThread* current);
222220
static void multianewarray4_C(Klass* klass, int len1, int len2, int len3, int len4, JavaThread* current);
223221
static void multianewarray5_C(Klass* klass, int len1, int len2, int len3, int len4, int len5, JavaThread* current);
@@ -282,7 +280,6 @@ class OptoRuntime : public AllStatic {
282280
static address new_instance_Java() { return _new_instance_Java; }
283281
static address new_array_Java() { return _new_array_Java; }
284282
static address new_array_nozero_Java() { return _new_array_nozero_Java; }
285-
static address multianewarray2_Java() { return _multianewarray2_Java; }
286283
static address multianewarray3_Java() { return _multianewarray3_Java; }
287284
static address multianewarray4_Java() { return _multianewarray4_Java; }
288285
static address multianewarray5_Java() { return _multianewarray5_Java; }
@@ -329,11 +326,6 @@ class OptoRuntime : public AllStatic {
329326

330327
static const TypeFunc* multianewarray_Type(int ndim); // multianewarray
331328

332-
static inline const TypeFunc* multianewarray2_Type() {
333-
assert(_multianewarray2_Type != nullptr, "should be initialized");
334-
return _multianewarray2_Type;
335-
}
336-
337329
static inline const TypeFunc* multianewarray3_Type() {
338330
assert(_multianewarray3_Type != nullptr, "should be initialized");
339331
return _multianewarray3_Type;

src/hotspot/share/runtime/stubDeclarations.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,6 @@
218218
do_stub(new_instance, 0, true, false) \
219219
do_stub(new_array, 0, true, false) \
220220
do_stub(new_array_nozero, 0, true, false) \
221-
do_stub(multianewarray2, 0, true, false) \
222221
do_stub(multianewarray3, 0, true, false) \
223222
do_stub(multianewarray4, 0, true, false) \
224223
do_stub(multianewarray5, 0, true, false) \
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright (c) 2026, BELLSOFT. 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+
/*
25+
* @test
26+
* @bug 8308105
27+
* @summary Test correctness of inlined 2D array allocation
28+
*
29+
* @run main/othervm -Xcomp -Xbatch -XX:-TieredCompilation compiler.allocation.TestMultiArrayAlloc
30+
* @run main/othervm -Xcomp -Xbatch -XX:-TieredCompilation -XX:+UseSerialGC compiler.allocation.TestMultiArrayAlloc
31+
* @run main/othervm -Xcomp -Xbatch -XX:-TieredCompilation -XX:+UseG1GC compiler.allocation.TestMultiArrayAlloc
32+
*
33+
* @requires vm.gc.Shenandoah & vm.gc.Z
34+
* @run main/othervm -Xcomp -Xbatch -XX:-TieredCompilation -XX:+UseShenandoahGC compiler.allocation.TestMultiArrayAlloc
35+
* @run main/othervm -Xcomp -Xbatch -XX:-TieredCompilation -XX:+UseZGC compiler.allocation.TestMultiArrayAlloc
36+
*/
37+
38+
package compiler.allocation;
39+
40+
public class TestMultiArrayAlloc {
41+
42+
static int[][] allocInt(int n1, int n2) { return new int[n1][n2]; }
43+
static Object[][] allocObj(int n1, int n2) { return new Object[n1][n2]; }
44+
static String[][] allocStr(int n1, int n2) { return new String[n1][n2]; }
45+
46+
static void check(boolean cond, String msg) { if (!cond) throw new RuntimeException(msg); }
47+
48+
static void testArrayContents() {
49+
int n1 = 10, n2 = 20;
50+
int[][] ints = allocInt(n1, n2);
51+
Object[][] objs = allocObj(n1, n2);
52+
String[][] strs = allocStr(n1, n2);
53+
check(ints.length == n1, "int outer length");
54+
check(objs.length == n1, "Object outer length");
55+
check(strs.length == n1, "String outer length");
56+
for (int i = 0; i < n1; i++) {
57+
check(ints[i] instanceof int[] && ints[i].length == n2, "int inner at " + i);
58+
check(objs[i] instanceof Object[] && objs[i].length == n2, "Object inner at " + i);
59+
check(strs[i] instanceof String[] && strs[i].length == n2, "String inner at " + i);
60+
for (int j = 0; j < n2; j++) {
61+
check(ints[i][j] == 0, "int not zero at [" + i + "][" + j + "]");
62+
check(objs[i][j] == null, "Object not null at [" + i + "][" + j + "]");
63+
check(strs[i][j] == null, "String not null at [" + i + "][" + j + "]");
64+
}
65+
}
66+
// length1 == 0
67+
int[][] b = allocInt(0, n2);
68+
check(b.length == 0, "int[0][n2] wrong length");
69+
// length2 == 0
70+
int[][] c = allocInt(n1, 0);
71+
for (int i = 0; i < n1; i++) {
72+
check(c[i].length == 0, "int[n1][0] inner length wrong at " + i);
73+
}
74+
}
75+
76+
static void testExceptions() {
77+
try {
78+
allocInt(-1, 5);
79+
throw new RuntimeException("expected NegativeArraySizeException for length1 < 0");
80+
} catch (NegativeArraySizeException e) { /* expected */ }
81+
try {
82+
allocInt(5, -1);
83+
throw new RuntimeException("expected NegativeArraySizeException for length2 < 0");
84+
} catch (NegativeArraySizeException e) { /* expected */ }
85+
try {
86+
allocInt(-1, -1);
87+
throw new RuntimeException("expected NegativeArraySizeException for both < 0");
88+
} catch (NegativeArraySizeException e) { /* expected */ }
89+
}
90+
91+
static void testRefsAfterGC() {
92+
int count = 5000, n1 = 4, n2 = 4;
93+
int[][][] refs = new int[count][][];
94+
for (int i = 0; i < count; i++) {
95+
refs[i] = allocInt(n1, n2);
96+
for (int j = 0; j < n1; j++) {
97+
refs[i][j][0] = i;
98+
}
99+
}
100+
System.gc();
101+
for (int i = 0; i < count; i++) {
102+
check(refs[i] != null, "GC collected outer array at " + i);
103+
for (int j = 0; j < n1; j++) {
104+
check(refs[i][j] != null, "GC collected inner array at [" + i + "][" + j + "]");
105+
}
106+
check(refs[i][0][0] == i, "GC corrupted value at " + i);
107+
}
108+
}
109+
110+
public static void main(String[] args) {
111+
testArrayContents();
112+
testExceptions();
113+
testRefsAfterGC();
114+
}
115+
}

0 commit comments

Comments
 (0)