+{"files":[{"patch":"@@ -1659,0 +1659,1 @@\n+ init_req( ValidLengthTest , topnode);\n@@ -1685,48 +1686,0 @@\n-\/\/=============================================================================\n-Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {\n- if (remove_dead_region(phase, can_reshape)) return this;\n- \/\/ Don't bother trying to transform a dead node\n- if (in(0) && in(0)->is_top()) return NULL;\n-\n- const Type* type = phase->type(Ideal_length());\n- if (type->isa_int() && type->is_int()->_hi < 0) {\n- if (can_reshape) {\n- PhaseIterGVN *igvn = phase->is_IterGVN();\n- \/\/ Unreachable fall through path (negative array length),\n- \/\/ the allocation can only throw so disconnect it.\n- Node* proj = proj_out_or_null(TypeFunc::Control);\n- Node* catchproj = NULL;\n- if (proj != NULL) {\n- for (DUIterator_Fast imax, i = proj->fast_outs(imax); i < imax; i++) {\n- Node *cn = proj->fast_out(i);\n- if (cn->is_Catch()) {\n- catchproj = cn->as_Multi()->proj_out_or_null(CatchProjNode::fall_through_index);\n- break;\n- }\n- }\n- }\n- if (catchproj != NULL && catchproj->outcnt() > 0 &&\n- (catchproj->outcnt() > 1 ||\n- catchproj->unique_out()->Opcode() != Op_Halt)) {\n- assert(catchproj->is_CatchProj(), \"must be a CatchProjNode\");\n- Node* nproj = catchproj->clone();\n- igvn->register_new_node_with_optimizer(nproj);\n-\n- Node *frame = new ParmNode( phase->C->start(), TypeFunc::FramePtr );\n- frame = phase->transform(frame);\n- \/\/ Halt & Catch Fire\n- Node* halt = new HaltNode(nproj, frame, \"unexpected negative array length\");\n- phase->C->root()->add_req(halt);\n- phase->transform(halt);\n-\n- igvn->replace_node(catchproj, phase->C->top());\n- return this;\n- }\n- } else {\n- \/\/ Can't correct it during regular GVN so register for IGVN\n- phase->C->record_for_igvn(this);\n- }\n- }\n- return NULL;\n-}\n-\n","filename":"src\/hotspot\/share\/opto\/callnode.cpp","additions":1,"deletions":48,"binary":false,"changes":49,"status":"modified"},{"patch":"@@ -916,0 +916,1 @@\n+ ValidLengthTest,\n@@ -925,0 +926,1 @@\n+ fields[ValidLengthTest] = TypeInt::BOOL;\n@@ -1019,4 +1021,2 @@\n- AllocateArrayNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio,\n- Node* size, Node* klass_node, Node* initial_test,\n- Node* count_val\n- )\n+ AllocateArrayNode(Compile* C, const TypeFunc* atype, Node* ctrl, Node* mem, Node* abio, Node* size, Node* klass_node,\n+ Node* initial_test, Node* count_val, Node* valid_length_test)\n@@ -1028,0 +1028,1 @@\n+ set_req(AllocateNode::ValidLengthTest, valid_length_test);\n@@ -1030,1 +1031,0 @@\n- virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);\n","filename":"src\/hotspot\/share\/opto\/callnode.hpp","additions":5,"deletions":5,"binary":false,"changes":10,"status":"modified"},{"patch":"@@ -2690,0 +2690,14 @@\n+ } else if (call->is_AllocateArray()) {\n+ Node* klass_node = call->in(AllocateNode::KlassNode);\n+ Node *length = call->in(AllocateNode::ALength);\n+ const Type* length_type = phase->type(length);\n+ const Type* klass_type = phase->type(klass_node);\n+ if (length_type == Type::TOP || klass_type == Type::TOP) {\n+ f[CatchProjNode::fall_through_index] = Type::TOP;\n+ } else {\n+ Node* valid_length_test = call->in(AllocateNode::ValidLengthTest);\n+ const Type* valid_length_test_t = phase->type(valid_length_test);\n+ if (valid_length_test_t->isa_int() && valid_length_test_t->is_int()->is_con(0)) {\n+ f[CatchProjNode::fall_through_index] = Type::TOP;\n+ }\n+ }\n","filename":"src\/hotspot\/share\/opto\/cfgnode.cpp","additions":14,"deletions":0,"binary":false,"changes":14,"status":"modified"},{"patch":"@@ -3745,1 +3745,1 @@\n- CallNode *call = n->in(0)->in(0)->as_Call();\n+ CallNode* call = n->in(0)->in(0)->as_Call();\n@@ -3754,1 +3754,1 @@\n- Node *arg0 = call->in(TypeFunc::Parms);\n+ Node* arg0 = call->in(TypeFunc::Parms);\n@@ -3759,3 +3759,2 @@\n- } else if (call->entry_point() == OptoRuntime::new_array_Java() &&\n- call->req() > TypeFunc::Parms+1 &&\n- call->is_CallStaticJava()) {\n+ } else if (call->entry_point() == OptoRuntime::new_array_Java() ||\n+ call->entry_point() == OptoRuntime::new_array_nozero_Java()) {\n@@ -3765,3 +3764,5 @@\n- Node *arg1 = call->in(TypeFunc::Parms+1);\n- if (arg1->is_Type() &&\n- arg1->as_Type()->type()->join(TypeInt::POS)->empty()) {\n+ assert(call->is_CallStaticJava(), \"static call expected\");\n+ assert(call->len() > call->req() && call->in(call->req()) != NULL, \"no precendent edge\");\n+ Node* valid_length_test = call->in(call->req());\n+ call->rm_prec(call->req());\n+ if (valid_length_test->find_int_con(1) == 0) {\n@@ -3770,0 +3771,2 @@\n+ assert(n->outcnt() == required_outcnt, \"malformed control flow\");\n+ continue;\n@@ -3778,0 +3781,7 @@\n+ } else if (n->is_PCTable() && n->in(0) && n->in(0)->in(0) && n->in(0)->in(0)->is_Call()) {\n+ CallNode* call = n->in(0)->in(0)->as_Call();\n+ if (call->entry_point() == OptoRuntime::new_array_Java() ||\n+ call->entry_point() == OptoRuntime::new_array_nozero_Java()) {\n+ assert(call->len() > call->req() && call->in(call->req()) != NULL, \"precedent edge expected\");\n+ call->rm_prec(call->req());\n+ }\n","filename":"src\/hotspot\/share\/opto\/compile.cpp","additions":18,"deletions":8,"binary":false,"changes":26,"status":"modified"},{"patch":"@@ -2741,1 +2741,3 @@\n- Node* norm = _gvn.transform( new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci) );\n+ Node* norm = new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci);\n+ _gvn.set_type_bottom(norm);\n+ C->record_for_igvn(norm);\n@@ -3982,0 +3984,9 @@\n+ const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type();\n+ Node* valid_length_test = C->top();\n+ if (ary_type->klass()->is_array_klass()) {\n+ BasicType bt = ary_type->klass()->as_array_klass()->element_type()->basic_type();\n+ jint max = TypeAryPtr::max_array_length(bt);\n+ Node* valid_length_cmp = _gvn.transform(new CmpUNode(length, intcon(max)));\n+ valid_length_test = _gvn.transform(new BoolNode(valid_length_cmp, BoolTest::le));\n+ }\n+\n@@ -3988,1 +3999,1 @@\n- length);\n+ length, valid_length_test);\n@@ -3995,1 +4006,0 @@\n- const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type();\n","filename":"src\/hotspot\/share\/opto\/graphKit.cpp","additions":13,"deletions":3,"binary":false,"changes":16,"status":"modified"},{"patch":"@@ -833,4 +833,0 @@\n- \/\/ May not have gone thru igvn yet so don't use _igvn.type(phi) (PhaseIdealLoop::is_counted_loop() sets the iv phi's type)\n- const TypeInteger* phi_t = phi->bottom_type()->is_integer(bt);\n- assert(phi_t->hi_as_long() >= phi_t->lo_as_long(), \"dead phi?\");\n- iters_limit = checked_cast<int>(MIN2((julong)iters_limit, (julong)(phi_t->hi_as_long() - phi_t->lo_as_long())));\n@@ -854,0 +850,5 @@\n+ \/\/ May not have gone thru igvn yet so don't use _igvn.type(phi) (PhaseIdealLoop::is_counted_loop() sets the iv phi's type)\n+ const TypeInteger* phi_t = phi->bottom_type()->is_integer(bt);\n+ assert(phi_t->hi_as_long() >= phi_t->lo_as_long(), \"dead phi?\");\n+ iters_limit = checked_cast<int>(MIN2((julong)iters_limit, (julong)(phi_t->hi_as_long() - phi_t->lo_as_long())));\n+\n","filename":"src\/hotspot\/share\/opto\/loopnode.cpp","additions":5,"deletions":4,"binary":false,"changes":9,"status":"modified"},{"patch":"@@ -1211,1 +1211,2 @@\n- address slow_call_address \/\/ Address of slow call\n+ address slow_call_address, \/\/ Address of slow call\n+ Node* valid_length_test \/\/ whether length is valid or not\n@@ -1396,0 +1397,3 @@\n+ if (valid_length_test != NULL) {\n+ call->add_prec(valid_length_test);\n+ }\n@@ -1878,1 +1882,1 @@\n- OptoRuntime::new_instance_Java());\n+ OptoRuntime::new_instance_Java(), NULL);\n@@ -1883,0 +1887,1 @@\n+ Node* valid_length_test = alloc->in(AllocateNode::ValidLengthTest);\n@@ -1897,1 +1902,1 @@\n- slow_call_address);\n+ slow_call_address, valid_length_test);\n","filename":"src\/hotspot\/share\/opto\/macro.cpp","additions":8,"deletions":3,"binary":false,"changes":11,"status":"modified"},{"patch":"@@ -95,2 +95,2 @@\n- address slow_call_address);\n- void yank_initalize_node(InitializeNode* node);\n+ address slow_call_address,\n+ Node* valid_length_test);\n","filename":"src\/hotspot\/share\/opto\/macro.hpp","additions":2,"deletions":2,"binary":false,"changes":4,"status":"modified"},{"patch":"@@ -131,2 +131,2 @@\n- assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1, \"unexpected node type\");\n- Node *use_c = use->is_If() ? use->in(0) : get_ctrl(use);\n+ assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1 || use->is_AllocateArray(), \"unexpected node type\");\n+ Node *use_c = (use->is_If() || use->is_AllocateArray()) ? use->in(0) : get_ctrl(use);\n@@ -169,2 +169,3 @@\n- assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1, \"unexpected node type\");\n- assert(u->in(1) == bol, \"\");\n+ assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1 || u->is_AllocateArray(), \"unexpected node type\");\n+ assert(u->is_AllocateArray() || u->in(1) == bol, \"\");\n+ assert(!u->is_AllocateArray() || u->in(AllocateNode::ValidLengthTest) == bol, \"wrong input to AllocateArray\");\n@@ -172,1 +173,1 @@\n- Node *u_ctrl = u->is_If() ? u->in(0) : get_ctrl(u);\n+ Node *u_ctrl = (u->is_If() || u->is_AllocateArray()) ? u->in(0) : get_ctrl(u);\n@@ -176,1 +177,1 @@\n- _igvn.replace_input_of(u, 1, x);\n+ _igvn.replace_input_of(u, u->is_AllocateArray() ? AllocateNode::ValidLengthTest : 1, x);\n","filename":"src\/hotspot\/share\/opto\/split_if.cpp","additions":7,"deletions":6,"binary":false,"changes":13,"status":"modified"},{"patch":"@@ -0,0 +1,79 @@\n+\/*\n+ * Copyright (c) 2021, Red Hat, Inc. All rights reserved.\n+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n+ *\n+ * This code is free software; you can redistribute it and\/or modify it\n+ * under the terms of the GNU General Public License version 2 only, as\n+ * published by the Free Software Foundation.\n+ *\n+ * This code is distributed in the hope that it will be useful, but WITHOUT\n+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n+ * version 2 for more details (a copy is included in the LICENSE file that\n+ * accompanied this code).\n+ *\n+ * You should have received a copy of the GNU General Public License version\n+ * 2 along with this work; if not, write to the Free Software Foundation,\n+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n+ *\n+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n+ * or visit www.oracle.com if you need additional information or have any\n+ * questions.\n+ *\/\n+\n+\/*\n+ * @test\n+ * bug 8278413\n+ * @summary C2 crash when allocating array of size too large\n+ * @library \/test\/lib \/\n+ * @build sun.hotspot.WhiteBox\n+ * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox\n+ * @run main\/othervm -ea -Xbootclasspath\/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestFailedAllocationBadGraph\n+ *\/\n+\n+import sun.hotspot.WhiteBox;\n+import java.lang.reflect.Method;\n+import compiler.whitebox.CompilerWhiteBoxTest;\n+\n+public class TestFailedAllocationBadGraph {\n+ private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();\n+\n+ private static long[] array;\n+ private static int field;\n+ private static volatile int barrier;\n+\n+ public static void main(String[] args) throws Exception {\n+ run(\"test1\");\n+ run(\"test2\");\n+ }\n+\n+ private static void run(String method) throws Exception {\n+ Method m = TestFailedAllocationBadGraph.class.getDeclaredMethod(method);\n+ WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION);\n+ if (!WHITE_BOX.isMethodCompiled(m) || WHITE_BOX.getMethodCompilationLevel(m) != CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) {\n+ throw new RuntimeException(\"should still be compiled\");\n+ }\n+ }\n+\n+ private static int test1() {\n+ int length = Integer.MAX_VALUE;\n+ try {\n+ array = new long[length];\n+ } catch (OutOfMemoryError outOfMemoryError) {\n+ barrier = 0x42;\n+ length = field;\n+ }\n+ return length;\n+ }\n+\n+ private static int test2() {\n+ int length = -1;\n+ try {\n+ array = new long[length];\n+ } catch (OutOfMemoryError outOfMemoryError) {\n+ barrier = 0x42;\n+ length = field;\n+ }\n+ return length;\n+ }\n+}\n","filename":"test\/hotspot\/jtreg\/compiler\/allocation\/TestFailedAllocationBadGraph.java","additions":79,"deletions":0,"binary":false,"changes":79,"status":"added"}]}
0 commit comments