From 63e4b5c8acdb678f17541b755205e0e4feb5809c Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Fri, 12 Aug 2022 21:42:12 +0000 Subject: [PATCH] 8292260: [BACKOUT] JDK-8279219: [REDO] C2 crash when allocating array of size too large Reviewed-by: stuefe Backport-of: 967a28c3d85fdde6d5eb48aa0edd8f7597772469 --- src/hotspot/share/opto/callnode.cpp | 49 +++++++++++- src/hotspot/share/opto/callnode.hpp | 10 +-- src/hotspot/share/opto/cfgnode.cpp | 11 --- src/hotspot/share/opto/compile.cpp | 29 +++---- src/hotspot/share/opto/graphKit.cpp | 16 +--- src/hotspot/share/opto/macro.cpp | 14 +--- src/hotspot/share/opto/macro.hpp | 3 +- src/hotspot/share/opto/split_if.cpp | 13 ++- .../TestAllocArrayAfterAllocNoUse.java | 52 ------------ .../allocation/TestCCPAllocateArray.java | 53 ------------ .../TestFailedAllocationBadGraph.java | 80 ------------------- 11 files changed, 75 insertions(+), 255 deletions(-) delete mode 100644 test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java delete mode 100644 test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java delete mode 100644 test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index ea5e0245ac8..9d8d9425529 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1378,7 +1378,6 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, init_req( KlassNode , klass_node); init_req( InitialTest , initial_test); init_req( ALength , topnode); - init_req( ValidLengthTest , topnode); C->add_macro_node(this); } @@ -1399,6 +1398,54 @@ void AllocateNode::compute_MemBar_redundancy(ciMethod* initializer) } } +//============================================================================= +Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { + if (remove_dead_region(phase, can_reshape)) return this; + // Don't bother trying to transform a dead node + if (in(0) && in(0)->is_top()) return NULL; + + const Type* type = phase->type(Ideal_length()); + if (type->isa_int() && type->is_int()->_hi < 0) { + if (can_reshape) { + PhaseIterGVN *igvn = phase->is_IterGVN(); + // Unreachable fall through path (negative array length), + // the allocation can only throw so disconnect it. + Node* proj = proj_out_or_null(TypeFunc::Control); + Node* catchproj = NULL; + if (proj != NULL) { + for (DUIterator_Fast imax, i = proj->fast_outs(imax); i < imax; i++) { + Node *cn = proj->fast_out(i); + if (cn->is_Catch()) { + catchproj = cn->as_Multi()->proj_out_or_null(CatchProjNode::fall_through_index); + break; + } + } + } + if (catchproj != NULL && catchproj->outcnt() > 0 && + (catchproj->outcnt() > 1 || + catchproj->unique_out()->Opcode() != Op_Halt)) { + assert(catchproj->is_CatchProj(), "must be a CatchProjNode"); + Node* nproj = catchproj->clone(); + igvn->register_new_node_with_optimizer(nproj); + + Node *frame = new ParmNode( phase->C->start(), TypeFunc::FramePtr ); + frame = phase->transform(frame); + // Halt & Catch Fire + Node* halt = new HaltNode(nproj, frame, "unexpected negative array length"); + phase->C->root()->add_req(halt); + phase->transform(halt); + + igvn->replace_node(catchproj, phase->C->top()); + return this; + } + } else { + // Can't correct it during regular GVN so register for IGVN + phase->C->record_for_igvn(this); + } + } + return NULL; +} + // Retrieve the length from the AllocateArrayNode. Narrow the type with a // CastII, if appropriate. If we are not allowed to create new nodes, and // a CastII is appropriate, return NULL. diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index d21bfeb70a9..e4b99a2436b 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -839,7 +839,6 @@ class AllocateNode : public CallNode { KlassNode, // type (maybe dynamic) of the obj. InitialTest, // slow-path test (may be constant) ALength, // array length (or TOP if none) - ValidLengthTest, ParmLimit }; @@ -849,7 +848,6 @@ class AllocateNode : public CallNode { fields[KlassNode] = TypeInstPtr::NOTNULL; fields[InitialTest] = TypeInt::BOOL; fields[ALength] = t; // length (can be a bad length) - fields[ValidLengthTest] = TypeInt::BOOL; const TypeTuple *domain = TypeTuple::make(ParmLimit, fields); @@ -947,16 +945,18 @@ class AllocateNode : public CallNode { // class AllocateArrayNode : public AllocateNode { public: - AllocateArrayNode(Compile* C, const TypeFunc* atype, Node* ctrl, Node* mem, Node* abio, Node* size, Node* klass_node, - Node* initial_test, Node* count_val, Node* valid_length_test) + AllocateArrayNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio, + Node* size, Node* klass_node, Node* initial_test, + Node* count_val + ) : AllocateNode(C, atype, ctrl, mem, abio, size, klass_node, initial_test) { init_class_id(Class_AllocateArray); set_req(AllocateNode::ALength, count_val); - set_req(AllocateNode::ValidLengthTest, valid_length_test); } virtual int Opcode() const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); // Dig the length operand out of a array allocation site. Node* Ideal_length() { diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 9f61b401f99..67540f1885f 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -2352,17 +2352,6 @@ const Type* CatchNode::Value(PhaseGVN* phase) const { // Rethrows always throw exceptions, never return if (call->entry_point() == OptoRuntime::rethrow_stub()) { f[CatchProjNode::fall_through_index] = Type::TOP; - } else if (call->is_AllocateArray()) { - Node* klass_node = call->in(AllocateNode::KlassNode); - Node* length = call->in(AllocateNode::ALength); - const Type* length_type = phase->type(length); - const Type* klass_type = phase->type(klass_node); - Node* valid_length_test = call->in(AllocateNode::ValidLengthTest); - const Type* valid_length_test_t = phase->type(valid_length_test); - if (length_type == Type::TOP || klass_type == Type::TOP || valid_length_test_t == Type::TOP || - valid_length_test_t->is_int()->is_con(0)) { - f[CatchProjNode::fall_through_index] = Type::TOP; - } } else if( call->req() > TypeFunc::Parms ) { const Type *arg0 = phase->type( call->in(TypeFunc::Parms) ); // Check for null receiver to virtual or interface calls diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 4daf018fe7e..2b835aafebb 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3706,7 +3706,7 @@ bool Compile::final_graph_reshaping() { // 'fall-thru' path, so expected kids is 1 less. if (n->is_PCTable() && n->in(0) && n->in(0)->in(0)) { if (n->in(0)->in(0)->is_Call()) { - CallNode* call = n->in(0)->in(0)->as_Call(); + CallNode *call = n->in(0)->in(0)->as_Call(); if (call->entry_point() == OptoRuntime::rethrow_stub()) { required_outcnt--; // Rethrow always has 1 less kid } else if (call->req() > TypeFunc::Parms && @@ -3715,25 +3715,22 @@ bool Compile::final_graph_reshaping() { // detected that the virtual call will always result in a null // pointer exception. The fall-through projection of this CatchNode // will not be populated. - Node* arg0 = call->in(TypeFunc::Parms); + Node *arg0 = call->in(TypeFunc::Parms); if (arg0->is_Type() && arg0->as_Type()->type()->higher_equal(TypePtr::NULL_PTR)) { required_outcnt--; } - } else if (call->entry_point() == OptoRuntime::new_array_Java() || - call->entry_point() == OptoRuntime::new_array_nozero_Java()) { - // Check for illegal array length. In such case, the optimizer has + } else if (call->entry_point() == OptoRuntime::new_array_Java() && + call->req() > TypeFunc::Parms+1 && + call->is_CallStaticJava()) { + // Check for negative array length. In such case, the optimizer has // detected that the allocation attempt will always result in an // exception. There is no fall-through projection of this CatchNode . - assert(call->is_CallStaticJava(), "static call expected"); - assert(call->req() == call->jvms()->endoff() + 1, "missing extra input"); - Node* valid_length_test = call->in(call->req()-1); - call->del_req(call->req()-1); - if (valid_length_test->find_int_con(1) == 0) { + Node *arg1 = call->in(TypeFunc::Parms+1); + if (arg1->is_Type() && + arg1->as_Type()->type()->join(TypeInt::POS)->empty()) { required_outcnt--; } - assert(n->outcnt() == required_outcnt, "malformed control flow"); - continue; } } } @@ -3742,14 +3739,6 @@ bool Compile::final_graph_reshaping() { record_method_not_compilable("malformed control flow"); return true; // Not all targets reachable! } - } else if (n->is_PCTable() && n->in(0) && n->in(0)->in(0) && n->in(0)->in(0)->is_Call()) { - CallNode* call = n->in(0)->in(0)->as_Call(); - if (call->entry_point() == OptoRuntime::new_array_Java() || - call->entry_point() == OptoRuntime::new_array_nozero_Java()) { - assert(call->is_CallStaticJava(), "static call expected"); - assert(call->req() == call->jvms()->endoff() + 1, "missing extra input"); - call->del_req(call->req()-1); // valid length test useless now - } } // Check that I actually visited all kids. Unreached kids // must be infinite loops. diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 688ac387158..b44bc313fb0 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -2593,9 +2593,7 @@ void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool sep // Make a catch node with just two handlers: fall-through and catch-all Node* i_o = _gvn.transform( new ProjNode(call, TypeFunc::I_O, separate_io_proj) ); Node* catc = _gvn.transform( new CatchNode(control(), i_o, 2) ); - Node* norm = new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci); - _gvn.set_type_bottom(norm); - C->record_for_igvn(norm); + Node* norm = _gvn.transform( new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci) ); Node* excp = _gvn.transform( new CatchProjNode(catc, CatchProjNode::catch_all_index, CatchProjNode::no_handler_bci) ); { PreserveJVMState pjvms(this); @@ -3731,28 +3729,20 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable) initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn); } - const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type(); - Node* valid_length_test = _gvn.intcon(1); - if (ary_type->klass()->is_array_klass()) { - BasicType bt = ary_type->klass()->as_array_klass()->element_type()->basic_type(); - jint max = TypeAryPtr::max_array_length(bt); - Node* valid_length_cmp = _gvn.transform(new CmpUNode(length, intcon(max))); - valid_length_test = _gvn.transform(new BoolNode(valid_length_cmp, BoolTest::le)); - } - // Create the AllocateArrayNode and its result projections AllocateArrayNode* alloc = new AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT), control(), mem, i_o(), size, klass_node, initial_slow_test, - length, valid_length_test); + length); // Cast to correct type. Note that the klass_node may be constant or not, // and in the latter case the actual array type will be inexact also. // (This happens via a non-constant argument to inline_native_newArray.) // In any case, the value of klass_node provides the desired array type. const TypeInt* length_type = _gvn.find_int_type(length); + const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type(); if (ary_type->isa_aryptr() && length_type != NULL) { // Try to get a better type than POS for the size ary_type = ary_type->is_aryptr()->cast_to_size(length_type); diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 7a35cd87065..b66982ffdd5 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1288,8 +1288,7 @@ void PhaseMacroExpand::expand_allocate_common( AllocateNode* alloc, // allocation node to be expanded Node* length, // array length for an array allocation const TypeFunc* slow_call_type, // Type of slow call - address slow_call_address, // Address of slow call - Node* valid_length_test // whether length is valid or not + address slow_call_address // Address of slow call ) { @@ -1629,12 +1628,6 @@ void PhaseMacroExpand::expand_allocate_common( // Copy debug information and adjust JVMState information, then replace // allocate node with the call copy_call_debug_info((CallNode *) alloc, call); - // For array allocations, copy the valid length check to the call node so Compile::final_graph_reshaping() can verify - // that the call has the expected number of CatchProj nodes (in case the allocation always fails and the fallthrough - // path dies). - if (valid_length_test != NULL) { - call->add_req(valid_length_test); - } if (!always_slow) { call->set_cnt(PROB_UNLIKELY_MAG(4)); // Same effect as RC_UNCOMMON. } else { @@ -1989,12 +1982,11 @@ Node* PhaseMacroExpand::prefetch_allocation(Node* i_o, Node*& needgc_false, void PhaseMacroExpand::expand_allocate(AllocateNode *alloc) { expand_allocate_common(alloc, NULL, OptoRuntime::new_instance_Type(), - OptoRuntime::new_instance_Java(), NULL); + OptoRuntime::new_instance_Java()); } void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) { Node* length = alloc->in(AllocateNode::ALength); - Node* valid_length_test = alloc->in(AllocateNode::ValidLengthTest); InitializeNode* init = alloc->initialization(); Node* klass_node = alloc->in(AllocateNode::KlassNode); ciKlass* k = _igvn.type(klass_node)->is_klassptr()->klass(); @@ -2009,7 +2001,7 @@ void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) { } expand_allocate_common(alloc, length, OptoRuntime::new_array_Type(), - slow_call_address, valid_length_test); + slow_call_address); } //-------------------mark_eliminated_box---------------------------------- diff --git a/src/hotspot/share/opto/macro.hpp b/src/hotspot/share/opto/macro.hpp index 67852ce67b8..4be28161ed7 100644 --- a/src/hotspot/share/opto/macro.hpp +++ b/src/hotspot/share/opto/macro.hpp @@ -98,8 +98,7 @@ class PhaseMacroExpand : public Phase { void expand_allocate_common(AllocateNode* alloc, Node* length, const TypeFunc* slow_call_type, - address slow_call_address, - Node* valid_length_test); + address slow_call_address); Node *value_from_mem(Node *mem, Node *ctl, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc); Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc, Node_Stack *value_phis, int level); diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index 86efd58bcc2..ad7b0178d77 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -128,8 +128,8 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) { } } else { // We might see an Opaque1 from a loop limit check here - assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1 || use->is_AllocateArray(), "unexpected node type"); - Node *use_c = (use->is_If() || use->is_AllocateArray()) ? use->in(0) : get_ctrl(use); + assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1, "unexpected node type"); + Node *use_c = use->is_If() ? use->in(0) : get_ctrl(use); if (use_c == blk1 || use_c == blk2) { assert(use->is_CMove(), "unexpected node type"); continue; @@ -166,15 +166,14 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) { --j; } else { // We might see an Opaque1 from a loop limit check here - assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1 || u->is_AllocateArray(), "unexpected node type"); - assert(u->is_AllocateArray() || u->in(1) == bol, ""); - assert(!u->is_AllocateArray() || u->in(AllocateNode::ValidLengthTest) == bol, "wrong input to AllocateArray"); + assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1, "unexpected node type"); + assert(u->in(1) == bol, ""); // Get control block of either the CMove or the If input - Node *u_ctrl = (u->is_If() || u->is_AllocateArray()) ? u->in(0) : get_ctrl(u); + Node *u_ctrl = u->is_If() ? u->in(0) : get_ctrl(u); assert((u_ctrl != blk1 && u_ctrl != blk2) || u->is_CMove(), "won't converge"); Node *x = bol->clone(); register_new_node(x, u_ctrl); - _igvn.replace_input_of(u, u->is_AllocateArray() ? AllocateNode::ValidLengthTest : 1, x); + _igvn.replace_input_of(u, 1, x); --j; } } diff --git a/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java b/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java deleted file mode 100644 index e2bc9bfdd16..00000000000 --- a/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2022, Red Hat, Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 8279125 - * @summary fatal error: no reachable node should have no use - * @requires vm.flavor == "server" - * - * @run main/othervm -XX:-BackgroundCompilation -XX:-DoEscapeAnalysis TestAllocArrayAfterAllocNoUse - * - */ - -public class TestAllocArrayAfterAllocNoUse { - private static Object field; - - public static void main(String[] args) { - for (int i = 0; i < 20_000; i++) { - test(); - } - } - - private static void test() { - try { - final TestAllocArrayAfterAllocNoUse o = new TestAllocArrayAfterAllocNoUse(); - } catch (Exception e) { - final int[] array = new int[100]; - field = array; - } - - } -} diff --git a/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java b/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java deleted file mode 100644 index 9e312a79530..00000000000 --- a/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2022, Red Hat, Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 8279062 - * @summary C2: assert(t->meet(t0) == t) failed: Not monotonic after JDK-8278413 - * - * @run main/othervm -XX:-BackgroundCompilation TestCCPAllocateArray - * - */ - -public class TestCCPAllocateArray { - public static void main(String[] args) { - for (int i = 0; i < 20_000; i++) { - try { - test(); - } catch (OutOfMemoryError e) { - } - length(42); - } - } - - private static int[] test() { - int i = 2; - for (; i < 4; i *= 2); - return new int[length(i)]; - } - - private static int length(int i) { - return i == 4 ? Integer.MAX_VALUE : 0; - } -} diff --git a/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java b/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java deleted file mode 100644 index 549622b5a36..00000000000 --- a/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2022, Red Hat, Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * bug 8279219 - * @summary C2 crash when allocating array of size too large - * @requires vm.compiler2.enabled - * @library /test/lib / - * @build sun.hotspot.WhiteBox - * @run driver ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -ea -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestFailedAllocationBadGraph - */ - -import sun.hotspot.WhiteBox; -import java.lang.reflect.Method; -import compiler.whitebox.CompilerWhiteBoxTest; - -public class TestFailedAllocationBadGraph { - private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - - private static long[] array; - private static int field; - private static volatile int barrier; - - public static void main(String[] args) throws Exception { - run("test1"); - run("test2"); - } - - private static void run(String method) throws Exception { - Method m = TestFailedAllocationBadGraph.class.getDeclaredMethod(method); - WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); - if (!WHITE_BOX.isMethodCompiled(m) || WHITE_BOX.getMethodCompilationLevel(m) != CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) { - throw new RuntimeException("should still be compiled"); - } - } - - private static int test1() { - int length = Integer.MAX_VALUE; - try { - array = new long[length]; - } catch (OutOfMemoryError outOfMemoryError) { - barrier = 0x42; - length = field; - } - return length; - } - - private static int test2() { - int length = -1; - try { - array = new long[length]; - } catch (OutOfMemoryError outOfMemoryError) { - barrier = 0x42; - length = field; - } - return length; - } -}