8349479: C2: when a Type node becomes dead, make CFG path that uses it unreachable
Reviewed-by: chagedorn, vlivanov
This commit is contained in:
parent
45b7c74873
commit
bcac42aabc
@ -16297,7 +16297,8 @@ instruct ShouldNotReachHere() %{
|
|||||||
|
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (is_reachable()) {
|
if (is_reachable()) {
|
||||||
__ stop(_halt_reason);
|
const char* str = __ code_string(_halt_reason);
|
||||||
|
__ stop(str);
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
@ -8992,7 +8992,8 @@ instruct ShouldNotReachHere( )
|
|||||||
format %{ "ShouldNotReachHere" %}
|
format %{ "ShouldNotReachHere" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (is_reachable()) {
|
if (is_reachable()) {
|
||||||
__ stop(_halt_reason);
|
const char* str = __ code_string(_halt_reason);
|
||||||
|
__ stop(str);
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
ins_pipe(tail_call);
|
ins_pipe(tail_call);
|
||||||
|
@ -14699,7 +14699,8 @@ instruct ShouldNotReachHere() %{
|
|||||||
format %{ "ShouldNotReachHere" %}
|
format %{ "ShouldNotReachHere" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (is_reachable()) {
|
if (is_reachable()) {
|
||||||
__ stop(_halt_reason);
|
const char* str = __ code_string(_halt_reason);
|
||||||
|
__ stop(str);
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
ins_pipe(pipe_class_default);
|
ins_pipe(pipe_class_default);
|
||||||
|
@ -10893,7 +10893,8 @@ instruct ShouldNotReachHere() %{
|
|||||||
|
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (is_reachable()) {
|
if (is_reachable()) {
|
||||||
__ stop(_halt_reason);
|
const char* str = __ code_string(_halt_reason);
|
||||||
|
__ stop(str);
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
@ -10080,7 +10080,8 @@ instruct ShouldNotReachHere() %{
|
|||||||
format %{ "ILLTRAP; ShouldNotReachHere" %}
|
format %{ "ILLTRAP; ShouldNotReachHere" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (is_reachable()) {
|
if (is_reachable()) {
|
||||||
__ stop(_halt_reason);
|
const char* str = __ code_string(_halt_reason);
|
||||||
|
__ stop(str);
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
ins_pipe(pipe_class_dummy);
|
ins_pipe(pipe_class_dummy);
|
||||||
|
@ -2874,7 +2874,8 @@ instruct ShouldNotReachHere() %{
|
|||||||
format %{ "stop\t# ShouldNotReachHere" %}
|
format %{ "stop\t# ShouldNotReachHere" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (is_reachable()) {
|
if (is_reachable()) {
|
||||||
__ stop(_halt_reason);
|
const char* str = __ code_string(_halt_reason);
|
||||||
|
__ stop(str);
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
ins_pipe(pipe_slow);
|
ins_pipe(pipe_slow);
|
||||||
|
@ -44,10 +44,7 @@ void NativeCallStackPrinter::print_stack(const NativeCallStack* stack) const {
|
|||||||
if (created) {
|
if (created) {
|
||||||
stringStream ss(4 * K);
|
stringStream ss(4 * K);
|
||||||
stack->print_frame(&ss, pc);
|
stack->print_frame(&ss, pc);
|
||||||
const size_t len = ss.size();
|
(*cached_frame_text) = ss.as_string(&_text_storage);
|
||||||
char* store = NEW_ARENA_ARRAY(&_text_storage, char, len + 1);
|
|
||||||
memcpy(store, ss.base(), len + 1);
|
|
||||||
(*cached_frame_text) = store;
|
|
||||||
}
|
}
|
||||||
_out->print_raw_cr(*cached_frame_text);
|
_out->print_raw_cr(*cached_frame_text);
|
||||||
}
|
}
|
||||||
|
@ -820,6 +820,12 @@
|
|||||||
product(bool, UseStoreStoreForCtor, true, DIAGNOSTIC, \
|
product(bool, UseStoreStoreForCtor, true, DIAGNOSTIC, \
|
||||||
"Use StoreStore barrier instead of Release barrier at the end " \
|
"Use StoreStore barrier instead of Release barrier at the end " \
|
||||||
"of constructors") \
|
"of constructors") \
|
||||||
|
\
|
||||||
|
develop(bool, KillPathsReachableByDeadTypeNode, true, \
|
||||||
|
"When a Type node becomes top, make paths where the node is " \
|
||||||
|
"used dead by replacing them with a Halt node. Turning this off " \
|
||||||
|
"could corrupt the graph in rare cases and should be used with " \
|
||||||
|
"care.") \
|
||||||
|
|
||||||
// end of C2_FLAGS
|
// end of C2_FLAGS
|
||||||
|
|
||||||
|
@ -96,8 +96,14 @@ const Type* ConstraintCastNode::Value(PhaseGVN* phase) const {
|
|||||||
//------------------------------Ideal------------------------------------------
|
//------------------------------Ideal------------------------------------------
|
||||||
// Return a node which is more "ideal" than the current node. Strip out
|
// Return a node which is more "ideal" than the current node. Strip out
|
||||||
// control copies
|
// control copies
|
||||||
Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
Node* ConstraintCastNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||||
return (in(0) && remove_dead_region(phase, can_reshape)) ? this : nullptr;
|
if (in(0) != nullptr && remove_dead_region(phase, can_reshape)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if (in(1) != nullptr && phase->type(in(1)) != Type::TOP) {
|
||||||
|
return TypeNode::Ideal(phase, can_reshape);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint ConstraintCastNode::hash() const {
|
uint ConstraintCastNode::hash() const {
|
||||||
|
@ -46,6 +46,10 @@ public:
|
|||||||
virtual const RegMask &out_RegMask() const { return RegMask::Empty; }
|
virtual const RegMask &out_RegMask() const { return RegMask::Empty; }
|
||||||
virtual const RegMask &in_RegMask(uint) const { return RegMask::Empty; }
|
virtual const RegMask &in_RegMask(uint) const { return RegMask::Empty; }
|
||||||
|
|
||||||
|
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||||
|
return Node::Ideal(phase, can_reshape);
|
||||||
|
}
|
||||||
|
|
||||||
// Polymorphic factory method:
|
// Polymorphic factory method:
|
||||||
static ConNode* make(const Type *t);
|
static ConNode* make(const Type *t);
|
||||||
};
|
};
|
||||||
|
@ -689,7 +689,14 @@ bool Compile::push_thru_add(PhaseGVN* phase, Node* z, const TypeInteger* tz, con
|
|||||||
|
|
||||||
|
|
||||||
//------------------------------Ideal------------------------------------------
|
//------------------------------Ideal------------------------------------------
|
||||||
Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
Node* ConvI2LNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||||
|
if (in(1) != nullptr && phase->type(in(1)) != Type::TOP) {
|
||||||
|
Node* progress = TypeNode::Ideal(phase, can_reshape);
|
||||||
|
if (progress != nullptr) {
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const TypeLong* this_type = this->type()->is_long();
|
const TypeLong* this_type = this->type()->is_long();
|
||||||
if (can_reshape && !phase->C->post_loop_opts_phase()) {
|
if (can_reshape && !phase->C->post_loop_opts_phase()) {
|
||||||
// makes sure we run ::Value to potentially remove type assertion after loop opts
|
// makes sure we run ::Value to potentially remove type assertion after loop opts
|
||||||
@ -791,7 +798,14 @@ const Type* ConvL2INode::Value(PhaseGVN* phase) const {
|
|||||||
//------------------------------Ideal------------------------------------------
|
//------------------------------Ideal------------------------------------------
|
||||||
// Return a node which is more "ideal" than the current node.
|
// Return a node which is more "ideal" than the current node.
|
||||||
// Blow off prior masking to int
|
// Blow off prior masking to int
|
||||||
Node *ConvL2INode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
Node* ConvL2INode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||||
|
if (in(1) != nullptr && phase->type(in(1)) != Type::TOP) {
|
||||||
|
Node* progress = TypeNode::Ideal(phase, can_reshape);
|
||||||
|
if (progress != nullptr) {
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Node *andl = in(1);
|
Node *andl = in(1);
|
||||||
uint andl_op = andl->Opcode();
|
uint andl_op = andl->Opcode();
|
||||||
if( andl_op == Op_AndL ) {
|
if( andl_op == Op_AndL ) {
|
||||||
|
@ -90,6 +90,10 @@ Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
phase->type(in(IfTrue)) == Type::TOP) {
|
phase->type(in(IfTrue)) == Type::TOP) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
Node* progress = TypeNode::Ideal(phase, can_reshape);
|
||||||
|
if (progress != nullptr) {
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for Min/Max patterns. This is called before constants are pushed to the right input, as that transform can
|
// Check for Min/Max patterns. This is called before constants are pushed to the right input, as that transform can
|
||||||
// make BoolTests non-canonical.
|
// make BoolTests non-canonical.
|
||||||
|
@ -3076,3 +3076,78 @@ const Type* TypeNode::Value(PhaseGVN* phase) const { return _type; }
|
|||||||
uint TypeNode::ideal_reg() const {
|
uint TypeNode::ideal_reg() const {
|
||||||
return _type->ideal_reg();
|
return _type->ideal_reg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TypeNode::make_path_dead(PhaseIterGVN* igvn, PhaseIdealLoop* loop, Node* ctrl_use, uint j, const char* phase_str) {
|
||||||
|
Node* c = ctrl_use->in(j);
|
||||||
|
if (igvn->type(c) != Type::TOP) {
|
||||||
|
igvn->replace_input_of(ctrl_use, j, igvn->C->top());
|
||||||
|
create_halt_path(igvn, c, loop, phase_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This Type node is dead. It could be because the type that it captures and the type of the node computed from its
|
||||||
|
// inputs do not intersect anymore. That node has some uses along some control flow paths. Those control flow paths must
|
||||||
|
// be unreachable as using a dead value makes no sense. For the Type node to capture a narrowed down type, some control
|
||||||
|
// flow construct must guard the Type node (an If node usually). When the Type node becomes dead, the guard usually
|
||||||
|
// constant folds and the control flow that leads to the Type node becomes unreachable. There are cases where that
|
||||||
|
// doesn't happen, however. They are handled here by following uses of the Type node until a CFG or a Phi to find dead
|
||||||
|
// paths. The dead paths are then replaced by a Halt node.
|
||||||
|
void TypeNode::make_paths_from_here_dead(PhaseIterGVN* igvn, PhaseIdealLoop* loop, const char* phase_str) {
|
||||||
|
Unique_Node_List wq;
|
||||||
|
wq.push(this);
|
||||||
|
for (uint i = 0; i < wq.size(); ++i) {
|
||||||
|
Node* n = wq.at(i);
|
||||||
|
for (DUIterator_Fast kmax, k = n->fast_outs(kmax); k < kmax; k++) {
|
||||||
|
Node* u = n->fast_out(k);
|
||||||
|
if (u->is_CFG()) {
|
||||||
|
assert(!u->is_Region(), "Can't reach a Region without going through a Phi");
|
||||||
|
make_path_dead(igvn, loop, u, 0, phase_str);
|
||||||
|
} else if (u->is_Phi()) {
|
||||||
|
Node* r = u->in(0);
|
||||||
|
assert(r->is_Region() || r->is_top(), "unexpected Phi's control");
|
||||||
|
if (r->is_Region()) {
|
||||||
|
for (uint j = 1; j < u->req(); ++j) {
|
||||||
|
if (u->in(j) == n) {
|
||||||
|
make_path_dead(igvn, loop, r, j, phase_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wq.push(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeNode::create_halt_path(PhaseIterGVN* igvn, Node* c, PhaseIdealLoop* loop, const char* phase_str) const {
|
||||||
|
Node* frame = new ParmNode(igvn->C->start(), TypeFunc::FramePtr);
|
||||||
|
if (loop == nullptr) {
|
||||||
|
igvn->register_new_node_with_optimizer(frame);
|
||||||
|
} else {
|
||||||
|
loop->register_new_node(frame, igvn->C->start());
|
||||||
|
}
|
||||||
|
|
||||||
|
stringStream ss;
|
||||||
|
ss.print("dead path discovered by TypeNode during %s", phase_str);
|
||||||
|
|
||||||
|
Node* halt = new HaltNode(c, frame, ss.as_string(igvn->C->comp_arena()));
|
||||||
|
if (loop == nullptr) {
|
||||||
|
igvn->register_new_node_with_optimizer(halt);
|
||||||
|
} else {
|
||||||
|
loop->register_control(halt, loop->ltree_root(), c);
|
||||||
|
}
|
||||||
|
igvn->add_input_to(igvn->C->root(), halt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* TypeNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||||
|
if (KillPathsReachableByDeadTypeNode && can_reshape && Value(phase) == Type::TOP) {
|
||||||
|
PhaseIterGVN* igvn = phase->is_IterGVN();
|
||||||
|
Node* top = igvn->C->top();
|
||||||
|
ResourceMark rm;
|
||||||
|
make_paths_from_here_dead(igvn, nullptr, "igvn");
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node::Ideal(phase, can_reshape);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -155,6 +155,7 @@ class ParsePredicateNode;
|
|||||||
class PCTableNode;
|
class PCTableNode;
|
||||||
class PhaseCCP;
|
class PhaseCCP;
|
||||||
class PhaseGVN;
|
class PhaseGVN;
|
||||||
|
class PhaseIdealLoop;
|
||||||
class PhaseIterGVN;
|
class PhaseIterGVN;
|
||||||
class PhaseRegAlloc;
|
class PhaseRegAlloc;
|
||||||
class PhaseTransform;
|
class PhaseTransform;
|
||||||
@ -2044,12 +2045,17 @@ public:
|
|||||||
init_class_id(Class_Type);
|
init_class_id(Class_Type);
|
||||||
}
|
}
|
||||||
virtual const Type* Value(PhaseGVN* phase) const;
|
virtual const Type* Value(PhaseGVN* phase) const;
|
||||||
|
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||||
virtual const Type *bottom_type() const;
|
virtual const Type *bottom_type() const;
|
||||||
virtual uint ideal_reg() const;
|
virtual uint ideal_reg() const;
|
||||||
|
|
||||||
|
void make_path_dead(PhaseIterGVN* igvn, PhaseIdealLoop* loop, Node* ctrl_use, uint j, const char* phase_str);
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
virtual void dump_spec(outputStream *st) const;
|
virtual void dump_spec(outputStream *st) const;
|
||||||
virtual void dump_compact_spec(outputStream *st) const;
|
virtual void dump_compact_spec(outputStream *st) const;
|
||||||
#endif
|
#endif
|
||||||
|
void make_paths_from_here_dead(PhaseIterGVN* igvn, PhaseIdealLoop* loop, const char* phase_str);
|
||||||
|
void create_halt_path(PhaseIterGVN* igvn, Node* c, PhaseIdealLoop* loop, const char* phase_str) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "opto/opcodes.hpp"
|
#include "opto/opcodes.hpp"
|
||||||
|
@ -1835,6 +1835,11 @@ void PhaseCCP::analyze() {
|
|||||||
set_type(n, new_type);
|
set_type(n, new_type);
|
||||||
push_child_nodes_to_worklist(worklist, n);
|
push_child_nodes_to_worklist(worklist, n);
|
||||||
}
|
}
|
||||||
|
if (KillPathsReachableByDeadTypeNode && n->is_Type() && new_type == Type::TOP) {
|
||||||
|
// Keep track of Type nodes to kill CFG paths that use Type
|
||||||
|
// nodes that become dead.
|
||||||
|
_maybe_top_type_nodes.push(n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DEBUG_ONLY(verify_analyze(worklist_verify);)
|
DEBUG_ONLY(verify_analyze(worklist_verify);)
|
||||||
}
|
}
|
||||||
@ -2065,6 +2070,18 @@ Node *PhaseCCP::transform( Node *n ) {
|
|||||||
// track all visited nodes, so that we can remove the complement
|
// track all visited nodes, so that we can remove the complement
|
||||||
Unique_Node_List useful;
|
Unique_Node_List useful;
|
||||||
|
|
||||||
|
if (KillPathsReachableByDeadTypeNode) {
|
||||||
|
for (uint i = 0; i < _maybe_top_type_nodes.size(); ++i) {
|
||||||
|
Node* type_node = _maybe_top_type_nodes.at(i);
|
||||||
|
if (type(type_node) == Type::TOP) {
|
||||||
|
ResourceMark rm;
|
||||||
|
type_node->as_Type()->make_paths_from_here_dead(this, nullptr, "ccp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(_maybe_top_type_nodes.size() == 0, "we don't need type nodes");
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the traversal.
|
// Initialize the traversal.
|
||||||
// This CCP pass may prove that no exit test for a loop ever succeeds (i.e. the loop is infinite). In that case,
|
// This CCP pass may prove that no exit test for a loop ever succeeds (i.e. the loop is infinite). In that case,
|
||||||
// the logic below doesn't follow any path from Root to the loop body: there's at least one such path but it's proven
|
// the logic below doesn't follow any path from Root to the loop body: there's at least one such path but it's proven
|
||||||
|
@ -608,6 +608,7 @@ protected:
|
|||||||
// Should be replaced with combined CCP & GVN someday.
|
// Should be replaced with combined CCP & GVN someday.
|
||||||
class PhaseCCP : public PhaseIterGVN {
|
class PhaseCCP : public PhaseIterGVN {
|
||||||
Unique_Node_List _root_and_safepoints;
|
Unique_Node_List _root_and_safepoints;
|
||||||
|
Unique_Node_List _maybe_top_type_nodes;
|
||||||
// Non-recursive. Use analysis to transform single Node.
|
// Non-recursive. Use analysis to transform single Node.
|
||||||
virtual Node* transform_once(Node* n);
|
virtual Node* transform_once(Node* n);
|
||||||
|
|
||||||
|
@ -437,6 +437,13 @@ char* stringStream::as_string(bool c_heap) const {
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* stringStream::as_string(Arena* arena) const {
|
||||||
|
char* copy = NEW_ARENA_ARRAY(arena, char, _written + 1);
|
||||||
|
::memcpy(copy, _buffer, _written);
|
||||||
|
copy[_written] = '\0'; // terminating null
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
stringStream::~stringStream() {
|
stringStream::~stringStream() {
|
||||||
if (!_is_fixed && _buffer != _small_buffer) {
|
if (!_is_fixed && _buffer != _small_buffer) {
|
||||||
FREE_C_HEAP_ARRAY(char, _buffer);
|
FREE_C_HEAP_ARRAY(char, _buffer);
|
||||||
|
@ -270,6 +270,7 @@ class stringStream : public outputStream {
|
|||||||
bool is_empty() const { return _buffer[0] == '\0'; }
|
bool is_empty() const { return _buffer[0] == '\0'; }
|
||||||
// Copy to a resource, or C-heap, array as requested
|
// Copy to a resource, or C-heap, array as requested
|
||||||
char* as_string(bool c_heap = false) const;
|
char* as_string(bool c_heap = false) const;
|
||||||
|
char* as_string(Arena* arena) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class fileStream : public outputStream {
|
class fileStream : public outputStream {
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025, 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 8349479
|
||||||
|
* @summary C2: when a Type node becomes dead, make CFG path that uses it unreachable
|
||||||
|
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement
|
||||||
|
* -XX:CompileCommand=dontinline,TestGuardOfCastIIDoesntFold::notInlined
|
||||||
|
* TestGuardOfCastIIDoesntFold
|
||||||
|
* @run main TestGuardOfCastIIDoesntFold
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TestGuardOfCastIIDoesntFold {
|
||||||
|
private static volatile int volatileField;
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
for (int i = 0; i < 20_000; i++) {
|
||||||
|
test1(1, 0, 0, false);
|
||||||
|
helper1(1, 0, 0, true);
|
||||||
|
helper2(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int test1(int i, int j, int k, boolean flag) {
|
||||||
|
int l;
|
||||||
|
for (l = 0; l < 10; l++) {
|
||||||
|
}
|
||||||
|
j = helper2(j, l);
|
||||||
|
return helper1(i, j, k, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int helper2(int j, int l) {
|
||||||
|
if (l == 10) {
|
||||||
|
j = Integer.MAX_VALUE-1;
|
||||||
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int helper1(int i, int j, int k, boolean flag) {
|
||||||
|
if (flag) {
|
||||||
|
k = Integer.max(k, -2);
|
||||||
|
int[] array = new int[i + k];
|
||||||
|
notInlined(array);
|
||||||
|
return array[j];
|
||||||
|
}
|
||||||
|
volatileField = 42;
|
||||||
|
return volatileField;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void notInlined(int[] array) {
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,7 @@
|
|||||||
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates Xbatch
|
* compiler.predicates.assertion.TestAssertionPredicates Xbatch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -43,6 +44,7 @@
|
|||||||
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates NoTieredCompilation
|
* compiler.predicates.assertion.TestAssertionPredicates NoTieredCompilation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -54,6 +56,7 @@
|
|||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=inline,compiler.predicates.assertion.TestAssertionPredicates::inline
|
* -XX:CompileCommand=inline,compiler.predicates.assertion.TestAssertionPredicates::inline
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates Xcomp
|
* compiler.predicates.assertion.TestAssertionPredicates Xcomp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -65,6 +68,7 @@
|
|||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=inline,compiler.predicates.assertion.TestAssertionPredicates::inline
|
* -XX:CompileCommand=inline,compiler.predicates.assertion.TestAssertionPredicates::inline
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates XcompNoTiered
|
* compiler.predicates.assertion.TestAssertionPredicates XcompNoTiered
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -76,6 +80,7 @@
|
|||||||
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates LoopMaxUnroll0
|
* compiler.predicates.assertion.TestAssertionPredicates LoopMaxUnroll0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -87,6 +92,7 @@
|
|||||||
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates LoopMaxUnroll2
|
* compiler.predicates.assertion.TestAssertionPredicates LoopMaxUnroll2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -98,6 +104,7 @@
|
|||||||
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates LoopUnrollLimit40
|
* compiler.predicates.assertion.TestAssertionPredicates LoopUnrollLimit40
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -109,6 +116,7 @@
|
|||||||
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates LoopUnrollLimit150
|
* compiler.predicates.assertion.TestAssertionPredicates LoopUnrollLimit150
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -120,6 +128,7 @@
|
|||||||
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates NoProfiledLoopPredicate
|
* compiler.predicates.assertion.TestAssertionPredicates NoProfiledLoopPredicate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -131,6 +140,7 @@
|
|||||||
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
|
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates DataUpdate
|
* compiler.predicates.assertion.TestAssertionPredicates DataUpdate
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -141,6 +151,7 @@
|
|||||||
* @run main/othervm -Xcomp -XX:-BlockLayoutByFrequency -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* @run main/othervm -Xcomp -XX:-BlockLayoutByFrequency -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates CloneDown
|
* compiler.predicates.assertion.TestAssertionPredicates CloneDown
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -152,6 +163,7 @@
|
|||||||
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
|
* @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates Stress
|
* compiler.predicates.assertion.TestAssertionPredicates Stress
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -163,6 +175,7 @@
|
|||||||
* @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
|
* @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:+StressGCM -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates Stress
|
* compiler.predicates.assertion.TestAssertionPredicates Stress
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -174,6 +187,7 @@
|
|||||||
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates NoLoopPredication
|
* compiler.predicates.assertion.TestAssertionPredicates NoLoopPredication
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -185,6 +199,7 @@
|
|||||||
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
* -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure
|
||||||
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=compileonly,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
* -XX:CompileCommand=dontinline,compiler.predicates.assertion.TestAssertionPredicates::*
|
||||||
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:-KillPathsReachableByDeadTypeNode
|
||||||
* compiler.predicates.assertion.TestAssertionPredicates NoLoopPredication
|
* compiler.predicates.assertion.TestAssertionPredicates NoLoopPredication
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user