--- old/src/hotspot/share/opto/callnode.cpp 2018-10-24 11:10:46.304914490 +0200 +++ new/src/hotspot/share/opto/callnode.cpp 2018-10-24 11:10:37.412893085 +0200 @@ -1623,7 +1623,10 @@ Node *n = ctrl_proj->in(0); if (n != NULL && n->is_Unlock()) { UnlockNode *unlock = n->as_Unlock(); - if (lock->obj_node()->eqv_uncast(unlock->obj_node()) && + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + Node* lock_obj = bs->step_over_gc_barrier(lock->obj_node()); + Node* unlock_obj = bs->step_over_gc_barrier(unlock->obj_node()); + if (lock_obj->eqv_uncast(unlock_obj) && BoxLockNode::same_slot(lock->box_node(), unlock->box_node()) && !unlock->is_eliminated()) { lock_ops.append(unlock); @@ -1668,7 +1671,10 @@ } if (ctrl->is_Lock()) { LockNode *lock = ctrl->as_Lock(); - if (lock->obj_node()->eqv_uncast(unlock->obj_node()) && + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + Node* lock_obj = bs->step_over_gc_barrier(lock->obj_node()); + Node* unlock_obj = bs->step_over_gc_barrier(unlock->obj_node()); + if (lock_obj->eqv_uncast(unlock_obj) && BoxLockNode::same_slot(lock->box_node(), unlock->box_node())) { lock_result = lock; } @@ -1699,7 +1705,10 @@ } if (lock1_node != NULL && lock1_node->is_Lock()) { LockNode *lock1 = lock1_node->as_Lock(); - if (lock->obj_node()->eqv_uncast(lock1->obj_node()) && + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + Node* lock_obj = bs->step_over_gc_barrier(lock->obj_node()); + Node* lock1_obj = bs->step_over_gc_barrier(lock1->obj_node()); + if (lock_obj->eqv_uncast(lock1_obj) && BoxLockNode::same_slot(lock->box_node(), lock1->box_node()) && !lock1->is_eliminated()) { lock_ops.append(lock1); @@ -1916,6 +1925,8 @@ return false; } + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + obj = bs->step_over_gc_barrier(obj); // Look for external lock for the same object. SafePointNode* sfn = this->as_SafePoint(); JVMState* youngest_jvms = sfn->jvms(); @@ -1926,6 +1937,7 @@ // Loop over monitors for (int idx = 0; idx < num_mon; idx++) { Node* obj_node = sfn->monitor_obj(jvms, idx); + obj_node = bs->step_over_gc_barrier(obj_node); BoxLockNode* box_node = sfn->monitor_box(jvms, idx)->as_BoxLock(); if ((box_node->stack_slot() < stk_slot) && obj_node->eqv_uncast(obj)) { return true; --- old/src/hotspot/share/opto/node.cpp 2018-10-24 11:10:55.132935742 +0200 +++ new/src/hotspot/share/opto/node.cpp 2018-10-24 11:10:46.421914772 +0200 @@ -899,13 +899,6 @@ return (Node*) this; } -bool Node::eqv_uncast(const Node* n) const { - BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - Node* obj1 = bs->step_over_gc_barrier(const_cast(this)); - Node* obj2 = bs->step_over_gc_barrier(const_cast(n)); - return (obj1->uncast() == obj2->uncast()); -} - // Find out of current node that matches opcode. Node* Node::find_out_with(int opcode) { for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { --- old/src/hotspot/share/opto/node.hpp 2018-10-24 11:11:04.124957388 +0200 +++ new/src/hotspot/share/opto/node.hpp 2018-10-24 11:10:55.249936023 +0200 @@ -457,9 +457,10 @@ // Strip away casting. (It is depth-limited.) Node* uncast() const; - // Return whether two Nodes are equivalent, after stripping casting - // and GC barriers. - bool eqv_uncast(const Node* n) const; + // Return whether two Nodes are equivalent, after stripping casting. + bool eqv_uncast(const Node* n) const { + return (this->uncast() == n->uncast()); + } // Find out of current node that matches opcode. Node* find_out_with(int opcode); --- /dev/null 2018-10-18 20:34:27.864823750 +0200 +++ new/test/hotspot/jtreg/compiler/gcbarriers/EqvUncastStepOverBarrier.java 2018-10-24 11:11:04.236957658 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018, 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 8212673 + * @summary Node::eqv_uncast() shouldn't step over load barriers unconditionally + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-UseOnStackReplacement -XX:-TieredCompilation EqvUncastStepOverBarrier + */ + +import sun.hotspot.WhiteBox; +import java.lang.reflect.Method; + +public class EqvUncastStepOverBarrier { + static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static Object field = new A(); + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 20_000; i++) { + test(); + test(); + test_helper(null, 0); + } + Method m = EqvUncastStepOverBarrier.class.getDeclaredMethod("test"); + WHITE_BOX.enqueueMethodForCompilation(m, 4); + if (!WHITE_BOX.isMethodCompiled(m, false)) { + throw new RuntimeException("Method compilation failed"); + } + } + + private static Object test() { + Object o = field; + if (o == null) {} + for (int i = 1; i < 100; i *= 2) { + int j = 0; + for (; j < 4; j++) ; + o = test_helper(o, j); + } + return o; + } + + private static Object test_helper(Object o, int j) { + if (j == 4) { + A a = (A) o; + o = a; + } else { + o = new Object(); + } + return o; + } + + private static class A { + } +}