8330157: C2: Add a stress flag for bailouts
Reviewed-by: chagedorn, thartmann
This commit is contained in:
parent
d809bc0e21
commit
d3f3c6a8cd
@ -398,7 +398,10 @@ PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher)
|
||||
Node *x = new GotoNode(nullptr);
|
||||
x->init_req(0, x);
|
||||
_goto = matcher.match_tree(x);
|
||||
assert(_goto != nullptr, "");
|
||||
assert(_goto != nullptr || C->failure_is_artificial(), "");
|
||||
if (C->failing()) {
|
||||
return;
|
||||
}
|
||||
_goto->set_req(0,_goto);
|
||||
|
||||
// Build the CFG in Reverse Post Order
|
||||
|
@ -70,6 +70,14 @@
|
||||
develop(bool, StressMethodHandleLinkerInlining, false, \
|
||||
"Stress inlining through method handle linkers") \
|
||||
\
|
||||
develop(bool, StressBailout, false, \
|
||||
"Perform bailouts randomly at C2 failing() checks") \
|
||||
\
|
||||
develop(uint, StressBailoutMean, 100000, \
|
||||
"The expected number of failing() checks made until " \
|
||||
"a random bailout.") \
|
||||
range(1, max_juint) \
|
||||
\
|
||||
develop(intx, OptoPrologueNops, 0, \
|
||||
"Insert this many extra nop instructions " \
|
||||
"in the prologue of every nmethod") \
|
||||
|
@ -479,6 +479,9 @@ void PhaseChaitin::Register_Allocate() {
|
||||
}
|
||||
|
||||
uint new_max_lrg_id = Split(_lrg_map.max_lrg_id(), &split_arena); // Split spilling LRG everywhere
|
||||
if (C->failing()) {
|
||||
return;
|
||||
}
|
||||
_lrg_map.set_max_lrg_id(new_max_lrg_id);
|
||||
// Bail out if unique gets too large (ie - unique > MaxNodeLimit - 2*NodeLimitFudgeFactor)
|
||||
// or we failed to split
|
||||
@ -551,6 +554,9 @@ void PhaseChaitin::Register_Allocate() {
|
||||
return;
|
||||
}
|
||||
uint new_max_lrg_id = Split(_lrg_map.max_lrg_id(), &split_arena); // Split spilling LRG everywhere
|
||||
if (C->failing()) {
|
||||
return;
|
||||
}
|
||||
_lrg_map.set_max_lrg_id(new_max_lrg_id);
|
||||
// Bail out if unique gets too large (ie - unique > MaxNodeLimit - 2*NodeLimitFudgeFactor)
|
||||
C->check_node_count(2 * NodeLimitFudgeFactor, "out of nodes after split");
|
||||
|
@ -720,7 +720,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
|
||||
}
|
||||
|
||||
if (StressLCM || StressGCM || StressIGVN || StressCCP ||
|
||||
StressIncrementalInlining || StressMacroExpansion || StressUnstableIfTraps) {
|
||||
StressIncrementalInlining || StressMacroExpansion || StressUnstableIfTraps || StressBailout) {
|
||||
initialize_stress_seed(directive);
|
||||
}
|
||||
|
||||
@ -798,7 +798,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
|
||||
assert(failure_reason() != nullptr, "expect reason for parse failure");
|
||||
stringStream ss;
|
||||
ss.print("method parse failed: %s", failure_reason());
|
||||
record_method_not_compilable(ss.as_string());
|
||||
record_method_not_compilable(ss.as_string() DEBUG_ONLY(COMMA true));
|
||||
return;
|
||||
}
|
||||
GraphKit kit(jvms);
|
||||
@ -973,7 +973,7 @@ Compile::Compile( ciEnv* ci_env,
|
||||
_types = new (comp_arena()) Type_Array(comp_arena());
|
||||
_node_hash = new (comp_arena()) NodeHash(comp_arena(), 255);
|
||||
|
||||
if (StressLCM || StressGCM) {
|
||||
if (StressLCM || StressGCM || StressBailout) {
|
||||
initialize_stress_seed(directive);
|
||||
}
|
||||
|
||||
@ -1018,6 +1018,7 @@ void Compile::Init(bool aliasing) {
|
||||
|
||||
#ifdef ASSERT
|
||||
_phase_optimize_finished = false;
|
||||
_phase_verify_ideal_loop = false;
|
||||
_exception_backedge = false;
|
||||
_type_verify = nullptr;
|
||||
#endif
|
||||
@ -1108,7 +1109,7 @@ void Compile::Init(bool aliasing) {
|
||||
#ifdef ASSERT
|
||||
// Verify that the current StartNode is valid.
|
||||
void Compile::verify_start(StartNode* s) const {
|
||||
assert(failing() || s == start(), "should be StartNode");
|
||||
assert(failing_internal() || s == start(), "should be StartNode");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1118,7 +1119,7 @@ void Compile::verify_start(StartNode* s) const {
|
||||
* the ideal graph.
|
||||
*/
|
||||
StartNode* Compile::start() const {
|
||||
assert (!failing(), "Must not have pending failure. Reason is: %s", failure_reason());
|
||||
assert (!failing_internal() || C->failure_is_artificial(), "Must not have pending failure. Reason is: %s", failure_reason());
|
||||
for (DUIterator_Fast imax, i = root()->fast_outs(imax); i < imax; i++) {
|
||||
Node* start = root()->fast_out(i);
|
||||
if (start->is_Start()) {
|
||||
@ -2114,7 +2115,7 @@ void Compile::inline_incrementally(PhaseIterGVN& igvn) {
|
||||
igvn_worklist()->ensure_empty(); // should be done with igvn
|
||||
|
||||
while (inline_incrementally_one()) {
|
||||
assert(!failing(), "inconsistent");
|
||||
assert(!failing_internal() || failure_is_artificial(), "inconsistent");
|
||||
}
|
||||
if (failing()) return;
|
||||
|
||||
@ -2157,7 +2158,7 @@ void Compile::process_late_inline_calls_no_inline(PhaseIterGVN& igvn) {
|
||||
igvn_worklist()->ensure_empty(); // should be done with igvn
|
||||
|
||||
while (inline_incrementally_one()) {
|
||||
assert(!failing(), "inconsistent");
|
||||
assert(!failing_internal() || failure_is_artificial(), "inconsistent");
|
||||
}
|
||||
if (failing()) return;
|
||||
|
||||
@ -2944,6 +2945,9 @@ void Compile::Code_Gen() {
|
||||
|
||||
// Build a proper-looking CFG
|
||||
PhaseCFG cfg(node_arena(), root(), matcher);
|
||||
if (failing()) {
|
||||
return;
|
||||
}
|
||||
_cfg = &cfg;
|
||||
{
|
||||
TracePhase tp("scheduler", &timers[_t_scheduler]);
|
||||
@ -4329,7 +4333,7 @@ void Compile::verify_graph_edges(bool no_dead_code) {
|
||||
// to backtrack and retry without subsuming loads. Other than this backtracking
|
||||
// behavior, the Compile's failure reason is quietly copied up to the ciEnv
|
||||
// by the logic in C2Compiler.
|
||||
void Compile::record_failure(const char* reason) {
|
||||
void Compile::record_failure(const char* reason DEBUG_ONLY(COMMA bool allow_multiple_failures)) {
|
||||
if (log() != nullptr) {
|
||||
log()->elem("failure reason='%s' phase='compile'", reason);
|
||||
}
|
||||
@ -4339,6 +4343,8 @@ void Compile::record_failure(const char* reason) {
|
||||
if (CaptureBailoutInformation) {
|
||||
_first_failure_details = new CompilationFailureInfo(reason);
|
||||
}
|
||||
} else {
|
||||
assert(!StressBailout || allow_multiple_failures, "should have handled previous failure.");
|
||||
}
|
||||
|
||||
if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) {
|
||||
@ -4366,7 +4372,9 @@ Compile::TracePhase::TracePhase(const char* name, elapsedTimer* accumulator)
|
||||
}
|
||||
|
||||
Compile::TracePhase::~TracePhase() {
|
||||
if (_compile->failing()) return;
|
||||
if (_compile->failing_internal()) {
|
||||
return; // timing code, not stressing bailouts.
|
||||
}
|
||||
#ifdef ASSERT
|
||||
if (PrintIdealNodeCount) {
|
||||
tty->print_cr("phase name='%s' nodes='%d' live='%d' live_graph_walk='%d'",
|
||||
@ -5057,6 +5065,22 @@ bool Compile::randomized_select(int count) {
|
||||
return (random() & RANDOMIZED_DOMAIN_MASK) < (RANDOMIZED_DOMAIN / count);
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
// Failures are geometrically distributed with probability 1/StressBailoutMean.
|
||||
bool Compile::fail_randomly() {
|
||||
if ((random() % StressBailoutMean) != 0) {
|
||||
return false;
|
||||
}
|
||||
record_failure("StressBailout");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Compile::failure_is_artificial() {
|
||||
assert(failing_internal(), "should be failing");
|
||||
return C->failure_reason_is("StressBailout");
|
||||
}
|
||||
#endif
|
||||
|
||||
CloneMap& Compile::clone_map() { return _clone_map; }
|
||||
void Compile::set_clone_map(Dict* d) { _clone_map._dict = d; }
|
||||
|
||||
@ -5144,7 +5168,7 @@ void Compile::sort_macro_nodes() {
|
||||
}
|
||||
|
||||
void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) {
|
||||
if (failing()) { return; }
|
||||
if (failing_internal()) { return; } // failing_internal to not stress bailouts from printing code.
|
||||
EventCompilerPhase event(UNTIMED);
|
||||
if (event.should_commit()) {
|
||||
CompilerEvent::PhaseEvent::post(event, C->_latest_stage_start_counter, cpt, C->_compile_id, level);
|
||||
|
@ -391,6 +391,8 @@ class Compile : public Phase {
|
||||
DEBUG_ONLY(Unique_Node_List* _modified_nodes;) // List of nodes which inputs were modified
|
||||
DEBUG_ONLY(bool _phase_optimize_finished;) // Used for live node verification while creating new nodes
|
||||
|
||||
DEBUG_ONLY(bool _phase_verify_ideal_loop;) // Are we in PhaseIdealLoop verification?
|
||||
|
||||
// Arenas for new-space and old-space nodes.
|
||||
// Swapped between using _node_arena.
|
||||
// The lifetime of the old-space nodes is during xform.
|
||||
@ -786,6 +788,12 @@ private:
|
||||
void set_post_loop_opts_phase() { _post_loop_opts_phase = true; }
|
||||
void reset_post_loop_opts_phase() { _post_loop_opts_phase = false; }
|
||||
|
||||
#ifdef ASSERT
|
||||
bool phase_verify_ideal_loop() const { return _phase_verify_ideal_loop; }
|
||||
void set_phase_verify_ideal_loop() { _phase_verify_ideal_loop = true; }
|
||||
void reset_phase_verify_ideal_loop() { _phase_verify_ideal_loop = false; }
|
||||
#endif
|
||||
|
||||
bool allow_macro_nodes() { return _allow_macro_nodes; }
|
||||
void reset_allow_macro_nodes() { _allow_macro_nodes = false; }
|
||||
|
||||
@ -815,7 +823,7 @@ private:
|
||||
ciEnv* env() const { return _env; }
|
||||
CompileLog* log() const { return _log; }
|
||||
|
||||
bool failing() const {
|
||||
bool failing_internal() const {
|
||||
return _env->failing() ||
|
||||
_failure_reason.get() != nullptr;
|
||||
}
|
||||
@ -827,6 +835,27 @@ private:
|
||||
|
||||
const CompilationFailureInfo* first_failure_details() const { return _first_failure_details; }
|
||||
|
||||
bool failing() {
|
||||
if (failing_internal()) {
|
||||
return true;
|
||||
}
|
||||
#ifdef ASSERT
|
||||
// Disable stress code for PhaseIdealLoop verification (would have cascading effects).
|
||||
if (phase_verify_ideal_loop()) {
|
||||
return false;
|
||||
}
|
||||
if (StressBailout) {
|
||||
return fail_randomly();
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
bool fail_randomly();
|
||||
bool failure_is_artificial();
|
||||
#endif
|
||||
|
||||
bool failure_reason_is(const char* r) const {
|
||||
return (r == _failure_reason.get()) ||
|
||||
(r != nullptr &&
|
||||
@ -834,11 +863,11 @@ private:
|
||||
strcmp(r, _failure_reason.get()) == 0);
|
||||
}
|
||||
|
||||
void record_failure(const char* reason);
|
||||
void record_method_not_compilable(const char* reason) {
|
||||
void record_failure(const char* reason DEBUG_ONLY(COMMA bool allow_multiple_failures = false));
|
||||
void record_method_not_compilable(const char* reason DEBUG_ONLY(COMMA bool allow_multiple_failures = false)) {
|
||||
env()->record_method_not_compilable(reason);
|
||||
// Record failure reason.
|
||||
record_failure(reason);
|
||||
record_failure(reason DEBUG_ONLY(COMMA allow_multiple_failures));
|
||||
}
|
||||
bool check_node_count(uint margin, const char* reason) {
|
||||
if (oom()) {
|
||||
|
@ -1527,8 +1527,8 @@ void PhaseCFG::schedule_late(VectorSet &visited, Node_Stack &stack) {
|
||||
C->record_failure(C2Compiler::retry_no_subsuming_loads());
|
||||
} else {
|
||||
// Bailout without retry when (early->_dom_depth > LCA->_dom_depth)
|
||||
assert(false, "graph should be schedulable");
|
||||
C->record_method_not_compilable("late schedule failed: incorrect graph");
|
||||
assert(C->failure_is_artificial(), "graph should be schedulable");
|
||||
C->record_method_not_compilable("late schedule failed: incorrect graph" DEBUG_ONLY(COMMA true));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1708,8 +1708,8 @@ void PhaseCFG::global_code_motion() {
|
||||
Block* block = get_block(i);
|
||||
if (!schedule_local(block, ready_cnt, visited, recalc_pressure_nodes)) {
|
||||
if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) {
|
||||
assert(false, "local schedule failed");
|
||||
C->record_method_not_compilable("local schedule failed");
|
||||
assert(C->failure_is_artificial(), "local schedule failed");
|
||||
C->record_method_not_compilable("local schedule failed" DEBUG_ONLY(COMMA true));
|
||||
}
|
||||
_regalloc = nullptr;
|
||||
return;
|
||||
|
@ -340,7 +340,9 @@ static inline void add_one_req(Node* dstphi, Node* src) {
|
||||
// having a control input of its exception map, rather than null. Such
|
||||
// regions do not appear except in this function, and in use_exception_state.
|
||||
void GraphKit::combine_exception_states(SafePointNode* ex_map, SafePointNode* phi_map) {
|
||||
if (failing()) return; // dying anyway...
|
||||
if (failing_internal()) {
|
||||
return; // dying anyway...
|
||||
}
|
||||
JVMState* ex_jvms = ex_map->_jvms;
|
||||
assert(ex_jvms->same_calls_as(phi_map->_jvms), "consistent call chains");
|
||||
assert(ex_jvms->stkoff() == phi_map->_jvms->stkoff(), "matching locals");
|
||||
@ -446,7 +448,7 @@ void GraphKit::combine_exception_states(SafePointNode* ex_map, SafePointNode* ph
|
||||
|
||||
//--------------------------use_exception_state--------------------------------
|
||||
Node* GraphKit::use_exception_state(SafePointNode* phi_map) {
|
||||
if (failing()) { stop(); return top(); }
|
||||
if (failing_internal()) { stop(); return top(); }
|
||||
Node* region = phi_map->control();
|
||||
Node* hidden_merge_mark = root();
|
||||
assert(phi_map->jvms()->map() == phi_map, "sanity: 1-1 relation");
|
||||
@ -2056,7 +2058,9 @@ Node* GraphKit::uncommon_trap(int trap_request,
|
||||
ciKlass* klass, const char* comment,
|
||||
bool must_throw,
|
||||
bool keep_exact_action) {
|
||||
if (failing()) stop();
|
||||
if (failing_internal()) {
|
||||
stop();
|
||||
}
|
||||
if (stopped()) return nullptr; // trap reachable?
|
||||
|
||||
// Note: If ProfileTraps is true, and if a deopt. actually
|
||||
|
@ -82,7 +82,7 @@ class GraphKit : public Phase {
|
||||
|
||||
#ifdef ASSERT
|
||||
~GraphKit() {
|
||||
assert(failing() || !has_exceptions(),
|
||||
assert(failing_internal() || !has_exceptions(),
|
||||
"unless compilation failed, user must call transfer_exceptions_into_jvms");
|
||||
}
|
||||
#endif
|
||||
@ -182,6 +182,7 @@ class GraphKit : public Phase {
|
||||
|
||||
// Tell if the compilation is failing.
|
||||
bool failing() const { return C->failing(); }
|
||||
bool failing_internal() const { return C->failing_internal(); }
|
||||
|
||||
// Set _map to null, signalling a stop to further bytecode execution.
|
||||
// Preserve the map intact for future use, and return it back to the caller.
|
||||
|
@ -1204,7 +1204,7 @@ bool PhaseCFG::schedule_local(Block* block, GrowableArray<int>& ready_cnt, Vecto
|
||||
// to the Compile object, and the C2Compiler will see it and retry.
|
||||
C->record_failure(C2Compiler::retry_no_subsuming_loads());
|
||||
} else {
|
||||
assert(false, "graph should be schedulable");
|
||||
assert(C->failure_is_artificial(), "graph should be schedulable");
|
||||
}
|
||||
// assert( phi_cnt == end_idx(), "did not schedule all" );
|
||||
return false;
|
||||
|
@ -4935,7 +4935,9 @@ void PhaseIdealLoop::verify() const {
|
||||
bool success = true;
|
||||
|
||||
PhaseIdealLoop phase_verify(_igvn, this);
|
||||
if (C->failing()) return;
|
||||
if (C->failing_internal()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify ctrl and idom of every node.
|
||||
success &= verify_idom_and_nodes(C->root(), &phase_verify);
|
||||
|
@ -1128,7 +1128,9 @@ private:
|
||||
_verify_only(verify_me == nullptr),
|
||||
_mode(LoopOptsVerify),
|
||||
_nodes_required(UINT_MAX) {
|
||||
DEBUG_ONLY(C->set_phase_verify_ideal_loop();)
|
||||
build_and_optimize();
|
||||
DEBUG_ONLY(C->reset_phase_verify_ideal_loop();)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -194,6 +194,9 @@ void Matcher::match( ) {
|
||||
}
|
||||
// One-time initialization of some register masks.
|
||||
init_spill_mask( C->root()->in(1) );
|
||||
if (C->failing()) {
|
||||
return;
|
||||
}
|
||||
_return_addr_mask = return_addr();
|
||||
#ifdef _LP64
|
||||
// Pointers take 2 slots in 64-bit land
|
||||
@ -287,10 +290,16 @@ void Matcher::match( ) {
|
||||
// preserve area, locks & pad2.
|
||||
|
||||
OptoReg::Name reg1 = warp_incoming_stk_arg(vm_parm_regs[i].first());
|
||||
if (C->failing()) {
|
||||
return;
|
||||
}
|
||||
if( OptoReg::is_valid(reg1))
|
||||
_calling_convention_mask[i].Insert(reg1);
|
||||
|
||||
OptoReg::Name reg2 = warp_incoming_stk_arg(vm_parm_regs[i].second());
|
||||
if (C->failing()) {
|
||||
return;
|
||||
}
|
||||
if( OptoReg::is_valid(reg2))
|
||||
_calling_convention_mask[i].Insert(reg2);
|
||||
|
||||
@ -386,7 +395,7 @@ void Matcher::match( ) {
|
||||
// Don't set control, it will confuse GCM since there are no uses.
|
||||
// The control will be set when this node is used first time
|
||||
// in find_base_for_derived().
|
||||
assert(_mach_null != nullptr, "");
|
||||
assert(_mach_null != nullptr || C->failure_is_artificial(), ""); // bailouts are handled below.
|
||||
|
||||
C->set_root(xroot->is_Root() ? xroot->as_Root() : nullptr);
|
||||
|
||||
@ -404,7 +413,7 @@ void Matcher::match( ) {
|
||||
assert(C->failure_reason() != nullptr, "graph lost: reason unknown");
|
||||
ss.print("graph lost: reason unknown");
|
||||
}
|
||||
C->record_method_not_compilable(ss.as_string());
|
||||
C->record_method_not_compilable(ss.as_string() DEBUG_ONLY(COMMA true));
|
||||
}
|
||||
if (C->failing()) {
|
||||
// delete old;
|
||||
@ -1439,10 +1448,16 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) {
|
||||
}
|
||||
// Grab first register, adjust stack slots and insert in mask.
|
||||
OptoReg::Name reg1 = warp_outgoing_stk_arg(first, begin_out_arg_area, out_arg_limit_per_call );
|
||||
if (C->failing()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (OptoReg::is_valid(reg1))
|
||||
rm->Insert( reg1 );
|
||||
// Grab second register (if any), adjust stack slots and insert in mask.
|
||||
OptoReg::Name reg2 = warp_outgoing_stk_arg(second, begin_out_arg_area, out_arg_limit_per_call );
|
||||
if (C->failing()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (OptoReg::is_valid(reg2))
|
||||
rm->Insert( reg2 );
|
||||
} // End of for all arguments
|
||||
@ -2679,6 +2694,10 @@ bool Matcher::gen_narrow_oop_implicit_null_checks() {
|
||||
|
||||
// Compute RegMask for an ideal register.
|
||||
const RegMask* Matcher::regmask_for_ideal_register(uint ideal_reg, Node* ret) {
|
||||
assert(!C->failing_internal() || C->failure_is_artificial(), "already failing.");
|
||||
if (C->failing()) {
|
||||
return nullptr;
|
||||
}
|
||||
const Type* t = Type::mreg2type[ideal_reg];
|
||||
if (t == nullptr) {
|
||||
assert(ideal_reg >= Op_VecA && ideal_reg <= Op_VecZ, "not a vector: %d", ideal_reg);
|
||||
@ -2709,7 +2728,10 @@ const RegMask* Matcher::regmask_for_ideal_register(uint ideal_reg, Node* ret) {
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
MachNode* mspill = match_tree(spill);
|
||||
assert(mspill != nullptr, "matching failed: %d", ideal_reg);
|
||||
assert(mspill != nullptr || C->failure_is_artificial(), "matching failed: %d", ideal_reg);
|
||||
if (C->failing()) {
|
||||
return nullptr;
|
||||
}
|
||||
// Handle generic vector operand case
|
||||
if (Matcher::supports_generic_vector_operands && t->isa_vect()) {
|
||||
specialize_mach_node(mspill);
|
||||
@ -2855,7 +2877,7 @@ bool Matcher::is_encode_and_store_pattern(const Node* n, const Node* m) {
|
||||
|
||||
#ifdef ASSERT
|
||||
bool Matcher::verify_after_postselect_cleanup() {
|
||||
assert(!C->failing(), "sanity");
|
||||
assert(!C->failing_internal() || C->failure_is_artificial(), "sanity");
|
||||
if (supports_generic_vector_operands) {
|
||||
Unique_Node_List useful;
|
||||
C->identify_useful_nodes(useful);
|
||||
|
@ -1715,7 +1715,7 @@ void PhaseOutput::fill_buffer(C2_MacroAssembler* masm, uint* blk_starts) {
|
||||
node_offsets[n->_idx] = masm->offset();
|
||||
}
|
||||
#endif
|
||||
assert(!C->failing(), "Should not reach here if failing.");
|
||||
assert(!C->failing_internal() || C->failure_is_artificial(), "Should not reach here if failing.");
|
||||
|
||||
// "Normal" instruction case
|
||||
DEBUG_ONLY(uint instr_offset = masm->offset());
|
||||
@ -3393,7 +3393,7 @@ uint PhaseOutput::scratch_emit_size(const Node* n) {
|
||||
n->emit(&masm, C->regalloc());
|
||||
|
||||
// Emitting into the scratch buffer should not fail
|
||||
assert (!C->failing(), "Must not have pending failure. Reason is: %s", C->failure_reason());
|
||||
assert(!C->failing_internal() || C->failure_is_artificial(), "Must not have pending failure. Reason is: %s", C->failure_reason());
|
||||
|
||||
if (is_branch) // Restore label.
|
||||
n->as_MachBranch()->label_set(saveL, save_bnum);
|
||||
|
@ -426,7 +426,7 @@ class Parse : public GraphKit {
|
||||
void set_parse_bci(int bci);
|
||||
|
||||
// Must this parse be aborted?
|
||||
bool failing() { return C->failing(); }
|
||||
bool failing() const { return C->failing_internal(); } // might have cascading effects, not stressing bailouts for now.
|
||||
|
||||
Block* rpo_at(int rpo) {
|
||||
assert(0 <= rpo && rpo < _block_count, "oob");
|
||||
|
@ -306,8 +306,8 @@ static Node* clone_node(Node* def, Block *b, Compile* C) {
|
||||
C->record_failure(C2Compiler::retry_no_subsuming_loads());
|
||||
} else {
|
||||
// Bailout without retry
|
||||
assert(false, "RA Split failed: attempt to clone node with anti_dependence");
|
||||
C->record_method_not_compilable("RA Split failed: attempt to clone node with anti_dependence");
|
||||
assert(C->failure_is_artificial(), "RA Split failed: attempt to clone node with anti_dependence");
|
||||
C->record_method_not_compilable("RA Split failed: attempt to clone node with anti_dependence" DEBUG_ONLY(COMMA true));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
59
test/hotspot/jtreg/compiler/debug/TestStressBailout.java
Normal file
59
test/hotspot/jtreg/compiler/debug/TestStressBailout.java
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. 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.
|
||||
*/
|
||||
|
||||
package compiler.debug;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @key stress randomness
|
||||
* @bug 8330157
|
||||
* @requires vm.debug == true & vm.compiler2.enabled & (vm.opt.AbortVMOnCompilationFailure == "null" | !vm.opt.AbortVMOnCompilationFailure)
|
||||
* @summary Basic tests for bailout stress flag.
|
||||
* @library /test/lib /
|
||||
* @run driver compiler.debug.TestStressBailout
|
||||
*/
|
||||
|
||||
public class TestStressBailout {
|
||||
|
||||
static void runTest(int invprob) throws Exception {
|
||||
String[] procArgs = {"-Xcomp", "-XX:-TieredCompilation", "-XX:+StressBailout",
|
||||
"-XX:StressBailoutMean=" + invprob, "-version"};
|
||||
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(procArgs);
|
||||
OutputAnalyzer out = new OutputAnalyzer(pb.start());
|
||||
out.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Random r = Utils.getRandomInstance();
|
||||
// Likely bail out on -version, for some low Mean value.
|
||||
runTest(r.nextInt(1, 10));
|
||||
// Higher value
|
||||
runTest(r.nextInt(10, 1_000_000));
|
||||
}
|
||||
}
|
@ -309,6 +309,13 @@ public class CtwRunner {
|
||||
// allocation allocate lots of memory
|
||||
"-XX:CompileCommand=memlimit,*.*,0"));
|
||||
|
||||
// Use this stress mode 10% of the time as it could make some long-running compilations likely to abort.
|
||||
if (rng.nextInt(10) == 0) {
|
||||
Args.add("-XX:+StressBailout");
|
||||
Args.add("-XX:StressBailoutMean=100000");
|
||||
Args.add("-XX:+CaptureBailoutInformation");
|
||||
}
|
||||
|
||||
for (String arg : CTW_EXTRA_ARGS.split(",")) {
|
||||
Args.add(arg);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user