Skip to content

Commit 04ad668

Browse files
committed
8279204: [BACKOUT] JDK-8278413: C2 crash when allocating array of size too large
Reviewed-by: chagedorn, kvn
1 parent 730f670 commit 04ad668

File tree

9 files changed

+75
-147
lines changed

9 files changed

+75
-147
lines changed

src/hotspot/share/opto/callnode.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1656,7 +1656,6 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype,
16561656
init_req( KlassNode , klass_node);
16571657
init_req( InitialTest , initial_test);
16581658
init_req( ALength , topnode);
1659-
init_req( ValidLengthTest , topnode);
16601659
C->add_macro_node(this);
16611660
}
16621661

@@ -1683,6 +1682,54 @@ Node *AllocateNode::make_ideal_mark(PhaseGVN *phase, Node* obj, Node* control, N
16831682
return mark_node;
16841683
}
16851684

1685+
//=============================================================================
1686+
Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
1687+
if (remove_dead_region(phase, can_reshape)) return this;
1688+
// Don't bother trying to transform a dead node
1689+
if (in(0) && in(0)->is_top()) return NULL;
1690+
1691+
const Type* type = phase->type(Ideal_length());
1692+
if (type->isa_int() && type->is_int()->_hi < 0) {
1693+
if (can_reshape) {
1694+
PhaseIterGVN *igvn = phase->is_IterGVN();
1695+
// Unreachable fall through path (negative array length),
1696+
// the allocation can only throw so disconnect it.
1697+
Node* proj = proj_out_or_null(TypeFunc::Control);
1698+
Node* catchproj = NULL;
1699+
if (proj != NULL) {
1700+
for (DUIterator_Fast imax, i = proj->fast_outs(imax); i < imax; i++) {
1701+
Node *cn = proj->fast_out(i);
1702+
if (cn->is_Catch()) {
1703+
catchproj = cn->as_Multi()->proj_out_or_null(CatchProjNode::fall_through_index);
1704+
break;
1705+
}
1706+
}
1707+
}
1708+
if (catchproj != NULL && catchproj->outcnt() > 0 &&
1709+
(catchproj->outcnt() > 1 ||
1710+
catchproj->unique_out()->Opcode() != Op_Halt)) {
1711+
assert(catchproj->is_CatchProj(), "must be a CatchProjNode");
1712+
Node* nproj = catchproj->clone();
1713+
igvn->register_new_node_with_optimizer(nproj);
1714+
1715+
Node *frame = new ParmNode( phase->C->start(), TypeFunc::FramePtr );
1716+
frame = phase->transform(frame);
1717+
// Halt & Catch Fire
1718+
Node* halt = new HaltNode(nproj, frame, "unexpected negative array length");
1719+
phase->C->root()->add_req(halt);
1720+
phase->transform(halt);
1721+
1722+
igvn->replace_node(catchproj, phase->C->top());
1723+
return this;
1724+
}
1725+
} else {
1726+
// Can't correct it during regular GVN so register for IGVN
1727+
phase->C->record_for_igvn(this);
1728+
}
1729+
}
1730+
return NULL;
1731+
}
1732+
16861733
// Retrieve the length from the AllocateArrayNode. Narrow the type with a
16871734
// CastII, if appropriate. If we are not allowed to create new nodes, and
16881735
// a CastII is appropriate, return NULL.

src/hotspot/share/opto/callnode.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,6 @@ class AllocateNode : public CallNode {
913913
KlassNode, // type (maybe dynamic) of the obj.
914914
InitialTest, // slow-path test (may be constant)
915915
ALength, // array length (or TOP if none)
916-
ValidLengthTest,
917916
ParmLimit
918917
};
919918

@@ -923,7 +922,6 @@ class AllocateNode : public CallNode {
923922
fields[KlassNode] = TypeInstPtr::NOTNULL;
924923
fields[InitialTest] = TypeInt::BOOL;
925924
fields[ALength] = t; // length (can be a bad length)
926-
fields[ValidLengthTest] = TypeInt::BOOL;
927925

928926
const TypeTuple *domain = TypeTuple::make(ParmLimit, fields);
929927

@@ -1018,16 +1016,18 @@ class AllocateNode : public CallNode {
10181016
//
10191017
class AllocateArrayNode : public AllocateNode {
10201018
public:
1021-
AllocateArrayNode(Compile* C, const TypeFunc* atype, Node* ctrl, Node* mem, Node* abio, Node* size, Node* klass_node,
1022-
Node* initial_test, Node* count_val, Node* valid_length_test)
1019+
AllocateArrayNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio,
1020+
Node* size, Node* klass_node, Node* initial_test,
1021+
Node* count_val
1022+
)
10231023
: AllocateNode(C, atype, ctrl, mem, abio, size, klass_node,
10241024
initial_test)
10251025
{
10261026
init_class_id(Class_AllocateArray);
10271027
set_req(AllocateNode::ALength, count_val);
1028-
set_req(AllocateNode::ValidLengthTest, valid_length_test);
10291028
}
10301029
virtual int Opcode() const;
1030+
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
10311031

10321032
// Dig the length operand out of a array allocation site.
10331033
Node* Ideal_length() {

src/hotspot/share/opto/cfgnode.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2687,20 +2687,6 @@ const Type* CatchNode::Value(PhaseGVN* phase) const {
26872687
// Rethrows always throw exceptions, never return
26882688
if (call->entry_point() == OptoRuntime::rethrow_stub()) {
26892689
f[CatchProjNode::fall_through_index] = Type::TOP;
2690-
} else if (call->is_AllocateArray()) {
2691-
Node* klass_node = call->in(AllocateNode::KlassNode);
2692-
Node *length = call->in(AllocateNode::ALength);
2693-
const Type* length_type = phase->type(length);
2694-
const Type* klass_type = phase->type(klass_node);
2695-
if (length_type == Type::TOP || klass_type == Type::TOP) {
2696-
f[CatchProjNode::fall_through_index] = Type::TOP;
2697-
} else {
2698-
Node* valid_length_test = call->in(AllocateNode::ValidLengthTest);
2699-
const Type* valid_length_test_t = phase->type(valid_length_test);
2700-
if (valid_length_test_t->isa_int() && valid_length_test_t->is_int()->is_con(0)) {
2701-
f[CatchProjNode::fall_through_index] = Type::TOP;
2702-
}
2703-
}
27042690
} else if( call->req() > TypeFunc::Parms ) {
27052691
const Type *arg0 = phase->type( call->in(TypeFunc::Parms) );
27062692
// Check for null receiver to virtual or interface calls

src/hotspot/share/opto/compile.cpp

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3742,7 +3742,7 @@ bool Compile::final_graph_reshaping() {
37423742
// 'fall-thru' path, so expected kids is 1 less.
37433743
if (n->is_PCTable() && n->in(0) && n->in(0)->in(0)) {
37443744
if (n->in(0)->in(0)->is_Call()) {
3745-
CallNode* call = n->in(0)->in(0)->as_Call();
3745+
CallNode *call = n->in(0)->in(0)->as_Call();
37463746
if (call->entry_point() == OptoRuntime::rethrow_stub()) {
37473747
required_outcnt--; // Rethrow always has 1 less kid
37483748
} else if (call->req() > TypeFunc::Parms &&
@@ -3751,25 +3751,22 @@ bool Compile::final_graph_reshaping() {
37513751
// detected that the virtual call will always result in a null
37523752
// pointer exception. The fall-through projection of this CatchNode
37533753
// will not be populated.
3754-
Node* arg0 = call->in(TypeFunc::Parms);
3754+
Node *arg0 = call->in(TypeFunc::Parms);
37553755
if (arg0->is_Type() &&
37563756
arg0->as_Type()->type()->higher_equal(TypePtr::NULL_PTR)) {
37573757
required_outcnt--;
37583758
}
3759-
} else if (call->entry_point() == OptoRuntime::new_array_Java() ||
3760-
call->entry_point() == OptoRuntime::new_array_nozero_Java()) {
3759+
} else if (call->entry_point() == OptoRuntime::new_array_Java() &&
3760+
call->req() > TypeFunc::Parms+1 &&
3761+
call->is_CallStaticJava()) {
37613762
// Check for negative array length. In such case, the optimizer has
37623763
// detected that the allocation attempt will always result in an
37633764
// exception. There is no fall-through projection of this CatchNode .
3764-
assert(call->is_CallStaticJava(), "static call expected");
3765-
assert(call->len() > call->req() && call->in(call->req()) != NULL, "no precendent edge");
3766-
Node* valid_length_test = call->in(call->req());
3767-
call->rm_prec(call->req());
3768-
if (valid_length_test->find_int_con(1) == 0) {
3765+
Node *arg1 = call->in(TypeFunc::Parms+1);
3766+
if (arg1->is_Type() &&
3767+
arg1->as_Type()->type()->join(TypeInt::POS)->empty()) {
37693768
required_outcnt--;
37703769
}
3771-
assert(n->outcnt() == required_outcnt, "malformed control flow");
3772-
continue;
37733770
}
37743771
}
37753772
}
@@ -3778,13 +3775,6 @@ bool Compile::final_graph_reshaping() {
37783775
record_method_not_compilable("malformed control flow");
37793776
return true; // Not all targets reachable!
37803777
}
3781-
} else if (n->is_PCTable() && n->in(0) && n->in(0)->in(0) && n->in(0)->in(0)->is_Call()) {
3782-
CallNode* call = n->in(0)->in(0)->as_Call();
3783-
if (call->entry_point() == OptoRuntime::new_array_Java() ||
3784-
call->entry_point() == OptoRuntime::new_array_nozero_Java()) {
3785-
assert(call->len() > call->req() && call->in(call->req()) != NULL, "precedent edge expected");
3786-
call->rm_prec(call->req());
3787-
}
37883778
}
37893779
// Check that I actually visited all kids. Unreached kids
37903780
// must be infinite loops.

src/hotspot/share/opto/graphKit.cpp

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,9 +2742,7 @@ void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool sep
27422742
// Make a catch node with just two handlers: fall-through and catch-all
27432743
Node* i_o = _gvn.transform( new ProjNode(call, TypeFunc::I_O, separate_io_proj) );
27442744
Node* catc = _gvn.transform( new CatchNode(control(), i_o, 2) );
2745-
Node* norm = new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci);
2746-
_gvn.set_type_bottom(norm);
2747-
C->record_for_igvn(norm);
2745+
Node* norm = _gvn.transform( new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci) );
27482746
Node* excp = _gvn.transform( new CatchProjNode(catc, CatchProjNode::catch_all_index, CatchProjNode::no_handler_bci) );
27492747

27502748
{ PreserveJVMState pjvms(this);
@@ -3985,28 +3983,20 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
39853983
initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
39863984
}
39873985

3988-
const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type();
3989-
Node* valid_length_test = C->top();
3990-
if (ary_type->klass()->is_array_klass()) {
3991-
BasicType bt = ary_type->klass()->as_array_klass()->element_type()->basic_type();
3992-
jint max = TypeAryPtr::max_array_length(bt);
3993-
Node* valid_length_cmp = _gvn.transform(new CmpUNode(length, intcon(max)));
3994-
valid_length_test = _gvn.transform(new BoolNode(valid_length_cmp, BoolTest::le));
3995-
}
3996-
39973986
// Create the AllocateArrayNode and its result projections
39983987
AllocateArrayNode* alloc
39993988
= new AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT),
40003989
control(), mem, i_o(),
40013990
size, klass_node,
40023991
initial_slow_test,
4003-
length, valid_length_test);
3992+
length);
40043993

40053994
// Cast to correct type. Note that the klass_node may be constant or not,
40063995
// and in the latter case the actual array type will be inexact also.
40073996
// (This happens via a non-constant argument to inline_native_newArray.)
40083997
// In any case, the value of klass_node provides the desired array type.
40093998
const TypeInt* length_type = _gvn.find_int_type(length);
3999+
const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type();
40104000
if (ary_type->isa_aryptr() && length_type != NULL) {
40114001
// Try to get a better type than POS for the size
40124002
ary_type = ary_type->is_aryptr()->cast_to_size(length_type);

src/hotspot/share/opto/macro.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,8 +1208,7 @@ void PhaseMacroExpand::expand_allocate_common(
12081208
AllocateNode* alloc, // allocation node to be expanded
12091209
Node* length, // array length for an array allocation
12101210
const TypeFunc* slow_call_type, // Type of slow call
1211-
address slow_call_address, // Address of slow call
1212-
Node* valid_length_test // whether length is valid or not
1211+
address slow_call_address // Address of slow call
12131212
)
12141213
{
12151214
Node* ctrl = alloc->in(TypeFunc::Control);
@@ -1394,9 +1393,6 @@ void PhaseMacroExpand::expand_allocate_common(
13941393
// Copy debug information and adjust JVMState information, then replace
13951394
// allocate node with the call
13961395
call->copy_call_debug_info(&_igvn, alloc);
1397-
if (valid_length_test != NULL) {
1398-
call->add_prec(valid_length_test);
1399-
}
14001396
if (expand_fast_path) {
14011397
call->set_cnt(PROB_UNLIKELY_MAG(4)); // Same effect as RC_UNCOMMON.
14021398
} else {
@@ -1879,12 +1875,11 @@ Node* PhaseMacroExpand::prefetch_allocation(Node* i_o, Node*& needgc_false,
18791875
void PhaseMacroExpand::expand_allocate(AllocateNode *alloc) {
18801876
expand_allocate_common(alloc, NULL,
18811877
OptoRuntime::new_instance_Type(),
1882-
OptoRuntime::new_instance_Java(), NULL);
1878+
OptoRuntime::new_instance_Java());
18831879
}
18841880

18851881
void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) {
18861882
Node* length = alloc->in(AllocateNode::ALength);
1887-
Node* valid_length_test = alloc->in(AllocateNode::ValidLengthTest);
18881883
InitializeNode* init = alloc->initialization();
18891884
Node* klass_node = alloc->in(AllocateNode::KlassNode);
18901885
ciKlass* k = _igvn.type(klass_node)->is_klassptr()->klass();
@@ -1899,7 +1894,7 @@ void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) {
18991894
}
19001895
expand_allocate_common(alloc, length,
19011896
OptoRuntime::new_array_Type(),
1902-
slow_call_address, valid_length_test);
1897+
slow_call_address);
19031898
}
19041899

19051900
//-------------------mark_eliminated_box----------------------------------

src/hotspot/share/opto/macro.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ class PhaseMacroExpand : public Phase {
9292
void expand_allocate_common(AllocateNode* alloc,
9393
Node* length,
9494
const TypeFunc* slow_call_type,
95-
address slow_call_address,
96-
Node* valid_length_test);
95+
address slow_call_address);
96+
void yank_initalize_node(InitializeNode* node);
9797
void yank_alloc_node(AllocateNode* alloc);
9898
Node *value_from_mem(Node *mem, Node *ctl, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc);
9999
Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc, Node_Stack *value_phis, int level);

src/hotspot/share/opto/split_if.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) {
128128
}
129129
} else {
130130
// We might see an Opaque1 from a loop limit check here
131-
assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1 || use->is_AllocateArray(), "unexpected node type");
132-
Node *use_c = (use->is_If() || use->is_AllocateArray()) ? use->in(0) : get_ctrl(use);
131+
assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1, "unexpected node type");
132+
Node *use_c = use->is_If() ? use->in(0) : get_ctrl(use);
133133
if (use_c == blk1 || use_c == blk2) {
134134
assert(use->is_CMove(), "unexpected node type");
135135
continue;
@@ -166,15 +166,14 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) {
166166
--j;
167167
} else {
168168
// We might see an Opaque1 from a loop limit check here
169-
assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1 || u->is_AllocateArray(), "unexpected node type");
170-
assert(u->is_AllocateArray() || u->in(1) == bol, "");
171-
assert(!u->is_AllocateArray() || u->in(AllocateNode::ValidLengthTest) == bol, "wrong input to AllocateArray");
169+
assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1, "unexpected node type");
170+
assert(u->in(1) == bol, "");
172171
// Get control block of either the CMove or the If input
173-
Node *u_ctrl = (u->is_If() || u->is_AllocateArray()) ? u->in(0) : get_ctrl(u);
172+
Node *u_ctrl = u->is_If() ? u->in(0) : get_ctrl(u);
174173
assert((u_ctrl != blk1 && u_ctrl != blk2) || u->is_CMove(), "won't converge");
175174
Node *x = bol->clone();
176175
register_new_node(x, u_ctrl);
177-
_igvn.replace_input_of(u, u->is_AllocateArray() ? AllocateNode::ValidLengthTest : 1, x);
176+
_igvn.replace_input_of(u, 1, x);
178177
--j;
179178
}
180179
}

test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java

Lines changed: 0 additions & 79 deletions
This file was deleted.

0 commit comments

Comments
 (0)