Skip to content
Permalink
Browse files
8261812: C2 compilation fails with assert(!had_error) failed: bad dom…
…inance

Reviewed-by: kvn, thartmann
  • Loading branch information
rwestrel committed Mar 5, 2021
1 parent 9755782 commit 2c0507ecd66193a8ca3cc53cfc58e0788658285e
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 23 deletions.
@@ -4793,3 +4793,27 @@ void Compile::igv_print_method_to_network(const char* phase_name) {
void Compile::add_native_invoker(RuntimeStub* stub) {
_native_invokers.append(stub);
}

Node* Compile::narrow_value(BasicType bt, Node* value, const Type* type, PhaseGVN* phase, bool transform_res) {
if (type != NULL && phase->type(value)->higher_equal(type)) {
return value;
}
Node* result = NULL;
if (bt == T_BYTE) {
result = phase->transform(new LShiftINode(value, phase->intcon(24)));
result = new RShiftINode(result, phase->intcon(24));
} else if (bt == T_BOOLEAN) {
result = new AndINode(value, phase->intcon(0xFF));
} else if (bt == T_CHAR) {
result = new AndINode(value,phase->intcon(0xFFFF));
} else {
assert(bt == T_SHORT, "unexpected narrow type");
result = phase->transform(new LShiftINode(value, phase->intcon(16)));
result = new RShiftINode(result, phase->intcon(16));
}
if (transform_res) {
result = phase->transform(result);
}
return result;
}

@@ -1192,9 +1192,10 @@ class Compile : public Phase {
bool has_exception_backedge() const { return _exception_backedge; }
#endif

static bool
push_thru_add(PhaseGVN* phase, Node* z, const TypeInteger* tz, const TypeInteger*& rx, const TypeInteger*& ry,
BasicType bt);
static bool push_thru_add(PhaseGVN* phase, Node* z, const TypeInteger* tz, const TypeInteger*& rx, const TypeInteger*& ry,
BasicType bt);

static Node* narrow_value(BasicType bt, Node* value, const Type* type, PhaseGVN* phase, bool transform_res);
};

#endif // SHARE_OPTO_COMPILE_HPP
@@ -450,6 +450,9 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
Node* n = val->in(MemNode::ValueIn);
BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
n = bs->step_over_gc_barrier(n);
if (is_subword_type(ft)) {
n = Compile::narrow_value(ft, n, phi_type, &_igvn, true);
}
values.at_put(j, n);
} else if(val->is_Proj() && val->in(0) == alloc) {
values.at_put(j, _igvn.zerocon(ft));
@@ -2079,12 +2079,14 @@ uint LoadNode::match_edge(uint idx) const {
// with the value stored truncated to a byte. If no truncation is
// needed, the replacement is done in LoadNode::Identity().
//
Node *LoadBNode::Ideal(PhaseGVN *phase, bool can_reshape) {
Node* LoadBNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* mem = in(MemNode::Memory);
Node* value = can_see_stored_value(mem,phase);
if( value && !phase->type(value)->higher_equal( _type ) ) {
Node *result = phase->transform( new LShiftINode(value, phase->intcon(24)) );
return new RShiftINode(result, phase->intcon(24));
if (value != NULL) {
Node* narrow = Compile::narrow_value(T_BYTE, value, _type, phase, false);
if (narrow != value) {
return narrow;
}
}
// Identity call will handle the case where truncation is not needed.
return LoadNode::Ideal(phase, can_reshape);
@@ -2114,8 +2116,12 @@ const Type* LoadBNode::Value(PhaseGVN* phase) const {
Node* LoadUBNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* mem = in(MemNode::Memory);
Node* value = can_see_stored_value(mem, phase);
if (value && !phase->type(value)->higher_equal(_type))
return new AndINode(value, phase->intcon(0xFF));
if (value != NULL) {
Node* narrow = Compile::narrow_value(T_BOOLEAN, value, _type, phase, false);
if (narrow != value) {
return narrow;
}
}
// Identity call will handle the case where truncation is not needed.
return LoadNode::Ideal(phase, can_reshape);
}
@@ -2141,11 +2147,15 @@ const Type* LoadUBNode::Value(PhaseGVN* phase) const {
// with the value stored truncated to a char. If no truncation is
// needed, the replacement is done in LoadNode::Identity().
//
Node *LoadUSNode::Ideal(PhaseGVN *phase, bool can_reshape) {
Node* LoadUSNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* mem = in(MemNode::Memory);
Node* value = can_see_stored_value(mem,phase);
if( value && !phase->type(value)->higher_equal( _type ) )
return new AndINode(value,phase->intcon(0xFFFF));
if (value != NULL) {
Node* narrow = Compile::narrow_value(T_CHAR, value, _type, phase, false);
if (narrow != value) {
return narrow;
}
}
// Identity call will handle the case where truncation is not needed.
return LoadNode::Ideal(phase, can_reshape);
}
@@ -2171,12 +2181,14 @@ const Type* LoadUSNode::Value(PhaseGVN* phase) const {
// with the value stored truncated to a short. If no truncation is
// needed, the replacement is done in LoadNode::Identity().
//
Node *LoadSNode::Ideal(PhaseGVN *phase, bool can_reshape) {
Node* LoadSNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* mem = in(MemNode::Memory);
Node* value = can_see_stored_value(mem,phase);
if( value && !phase->type(value)->higher_equal( _type ) ) {
Node *result = phase->transform( new LShiftINode(value, phase->intcon(16)) );
return new RShiftINode(result, phase->intcon(16));
if (value != NULL) {
Node* narrow = Compile::narrow_value(T_SHORT, value, _type, phase, false);
if (narrow != value) {
return narrow;
}
}
// Identity call will handle the case where truncation is not needed.
return LoadNode::Ideal(phase, can_reshape);
@@ -2586,19 +2586,18 @@ void Parse::do_one_bytecode() {
case Bytecodes::_i2b:
// Sign extend
a = pop();
a = _gvn.transform( new LShiftINode(a,_gvn.intcon(24)) );
a = _gvn.transform( new RShiftINode(a,_gvn.intcon(24)) );
push( a );
a = Compile::narrow_value(T_BYTE, a, NULL, &_gvn, true);
push(a);
break;
case Bytecodes::_i2s:
a = pop();
a = _gvn.transform( new LShiftINode(a,_gvn.intcon(16)) );
a = _gvn.transform( new RShiftINode(a,_gvn.intcon(16)) );
push( a );
a = Compile::narrow_value(T_SHORT, a, NULL, &_gvn, true);
push(a);
break;
case Bytecodes::_i2c:
a = pop();
push( _gvn.transform( new AndINode(a,_gvn.intcon(0xFFFF)) ) );
a = Compile::narrow_value(T_CHAR, a, NULL, &_gvn, true);
push(a);
break;

case Bytecodes::_i2f:
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2021, 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 8261812
* @summary C2 compilation fails with assert(!had_error) failed: bad dominance
*
* @run main/othervm -XX:-BackgroundCompilation TestValAtSafepointOverflowsInt
*
*/

public class TestValAtSafepointOverflowsInt {
private static volatile int volatileField;

public static void main(String[] args) {
for (int i = 0; i < 20_000; i++) {
testByte(true, false);
testByte(false, false);
testShort(true, false);
testShort(false, false);
testChar(true, false);
testChar(false, false);
}
testByte(true, true);
testShort(true, true);
testChar(true, true);
}

private static Object testByte(boolean flag, boolean flag2) {
int i;
// loop to delay constant folding
for (i = 0; i < 9; i++) {
}
C obj = new C();
if (flag) {
obj.byteField = (byte)(1 << i);
} else {
obj.byteField = (byte)(1 << (i+1));
}
// Phi for byte here for uncommon trap in never taken path below
// Phi inputs don't fit in a byte. Phi transfomed to top.
if (flag2) {
return obj;
}
return null;
}

private static Object testShort(boolean flag, boolean flag2) {
int i;
for (i = 0; i < 17; i++) {
}
C obj = new C();
if (flag) {
obj.shortField = (short)(1 << i);
} else {
obj.shortField = (short)(1 << (i+1));
}
if (flag2) {
return obj;
}
return null;
}

private static Object testChar(boolean flag, boolean flag2) {
int i;
for (i = 0; i < 17; i++) {
}
C obj = new C();
if (flag) {
obj.charField = (char)(1 << i);
} else {
obj.charField = (char)(1 << (i+1));
}
if (flag2) {
return obj;
}
return null;
}


static class C {
byte byteField;
short shortField;
char charField;
}

}

0 comments on commit 2c0507e

Please sign in to comment.