mirror of
https://github.com/openjdk/jdk.git
synced 2026-08-03 06:35:31 +00:00
8388441
This commit is contained in:
parent
cc278dbb8a
commit
b137ad640d
@ -1403,7 +1403,7 @@ bool CallStaticJavaNode::remove_unknown_flat_array_load(PhaseIterGVN* igvn, Node
|
||||
Node* CallStaticJavaNode::replace_is_substitutable(PhaseIterGVN* igvn) {
|
||||
Node* left = in(TypeFunc::Parms);
|
||||
Node* right = in(TypeFunc::Parms + 1);
|
||||
if (!InlineTypeNode::can_emit_substitutability_check(left, right)) {
|
||||
if (!InlineTypeNode::can_emit_substitutability_check(igvn, left, right)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -598,14 +598,32 @@ static bool check_cycle(ciInlineKlass* vk) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if 'lhs' and 'rhs' are the same oop, possibly wrapped in an InlineTypeNode.
|
||||
static bool same_oop(PhaseGVN* phase, Node* lhs, Node* rhs) {
|
||||
InlineTypeNode* lhs_inline = lhs->isa_InlineType();
|
||||
if (lhs_inline != nullptr && lhs_inline->is_allocated(phase)) {
|
||||
lhs = lhs_inline->get_oop();
|
||||
}
|
||||
InlineTypeNode* rhs_inline = rhs->isa_InlineType();
|
||||
if (rhs_inline != nullptr && rhs_inline->is_allocated(phase)) {
|
||||
rhs = rhs_inline->get_oop();
|
||||
}
|
||||
return lhs->eqv_uncast(rhs);
|
||||
}
|
||||
|
||||
// Check if a substitutability check between 'lhs' and 'rhs' can be implemented in IR
|
||||
bool InlineTypeNode::can_emit_substitutability_check(Node* lhs, Node* rhs) {
|
||||
bool InlineTypeNode::can_emit_substitutability_check(PhaseGVN* phase, Node* lhs, Node* rhs) {
|
||||
// We can't create new InlineTypeNodes after macro expansion
|
||||
if (!phase->C->allow_macro_nodes()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!lhs->bottom_type()->isa_ptr() ||
|
||||
(rhs != nullptr && !rhs->bottom_type()->isa_ptr())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rhs != nullptr && lhs->eqv_uncast(rhs)) {
|
||||
if (rhs != nullptr && same_oop(phase, lhs, rhs)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -641,7 +659,7 @@ bool InlineTypeNode::can_emit_substitutability_check(Node* lhs, Node* rhs) {
|
||||
|
||||
Node* lhs_fv = lhs_inline->field_value(i);
|
||||
Node* rhs_fv = rhs_inline != nullptr ? rhs_inline->field_value(i) : nullptr;
|
||||
if (!can_emit_substitutability_check(lhs_fv, rhs_fv)) {
|
||||
if (!can_emit_substitutability_check(phase, lhs_fv, rhs_fv)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -696,7 +714,7 @@ static Node* emit_substitutability_check_pointer(GraphKit* kit, PhiNode* result,
|
||||
}
|
||||
|
||||
Node* cmp = nullptr;
|
||||
if (lhs->eqv_uncast(rhs)) {
|
||||
if (same_oop(&gvn, lhs, rhs)) {
|
||||
cmp = kit->intcon(0);
|
||||
} else if (!lhs_type->is_ptr()->can_be_inline_type() || !rhs_type->is_ptr()->can_be_inline_type()) {
|
||||
// If one of the sides is not a value object, can only be substitutable if they are the same
|
||||
|
||||
@ -132,7 +132,7 @@ public:
|
||||
void store_flat_array(GraphKit* kit, Node* base, Node* idx);
|
||||
|
||||
// Implementation of the substitutability check for acmp
|
||||
static bool can_emit_substitutability_check(Node* lhs, Node* rhs);
|
||||
static bool can_emit_substitutability_check(PhaseGVN* phase, Node* lhs, Node* rhs);
|
||||
static Node* emit_substitutability_check(GraphKit* kit, Node* lhs, Node* rhs);
|
||||
|
||||
// Allocates the inline type (if not yet allocated)
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8388441
|
||||
* @summary Test acmp optimization when operands become known after macro expansion
|
||||
* @requires vm.compiler2.enabled
|
||||
* @library /test/lib
|
||||
* @enablePreview
|
||||
* @run main/othervm -XX:-TieredCompilation -Xbatch ${test.main.class}
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
public class TestSubstitutabilityExpansionAfterMacro {
|
||||
record Box(Object value) { }
|
||||
value record MyValue(Object value) { }
|
||||
|
||||
static boolean equals(Object a, Object b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
// Below tests trigger InlineTypeNode::can_emit_substitutability_check only
|
||||
// after macro expansion.
|
||||
|
||||
// EA leaves the right operand as Phi(InlineType<MyValue>, LoadN<Object>).
|
||||
// The cast creates a buffered InlineTypeNode whose oop is a cast of that phi.
|
||||
// After InlineTypeNode removal after macro expansion, both operands are equivalent.
|
||||
static boolean test1(boolean b) {
|
||||
Box box = b ? new Box(new MyValue(null)) : new Box(null);
|
||||
if (box.value == null) {
|
||||
box = new Box(new MyValue(null));
|
||||
}
|
||||
return equals((MyValue) box.value, box.value);
|
||||
}
|
||||
|
||||
// InlineTypeNode removal changes Phi(InlineType<Integer>(oop=null), exact Object)
|
||||
// to Phi(null, exact Object) as the right operand. The phi then becomes an exact
|
||||
// nullable Object and can_be_inline_type() changes to false after macro expansion.
|
||||
static boolean test2(Object obj, boolean b) {
|
||||
return equals(obj, b ? (Integer) null : new Object());
|
||||
}
|
||||
|
||||
// Both operands are phis of an InlineTypeNode and its oop. After InlineTypeNode
|
||||
// removal, both phis collapse to the same oop and the operands become equivalent
|
||||
// after macro expansion.
|
||||
static boolean test3(Object obj, boolean b) {
|
||||
Object left = b ? (MyValue) obj : obj;
|
||||
Object right = b ? obj : (MyValue) obj;
|
||||
// Use local acmp for fresh profiling
|
||||
return left == right;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Warmup and profile acmp with identity operands
|
||||
for (int i = 0; i < 10_000; i++) {
|
||||
equals(args, args);
|
||||
}
|
||||
Object obj = new Object();
|
||||
MyValue val = new MyValue(obj);
|
||||
for (int i = 0; i < 50_000; i++) {
|
||||
boolean b = (i & 1) == 0;
|
||||
Asserts.assertEQ(test1(b), true);
|
||||
Asserts.assertEQ(test2(b ? null : obj, b), b);
|
||||
Asserts.assertEQ(test3(val, b), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user