8328480: C2: SubTypeCheckNode in checkcast should use the klass constant of a unique concrete sub class
Reviewed-by: roland, kvn
This commit is contained in:
parent
1abb826210
commit
b486709b06
@ -3268,8 +3268,9 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac
|
|||||||
Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
||||||
Node* *failure_control) {
|
Node* *failure_control) {
|
||||||
kill_dead_locals(); // Benefit all the uncommon traps
|
kill_dead_locals(); // Benefit all the uncommon traps
|
||||||
const TypeKlassPtr *tk = _gvn.type(superklass)->is_klassptr()->try_improve();
|
const TypeKlassPtr* klass_ptr_type = _gvn.type(superklass)->is_klassptr();
|
||||||
const TypeOopPtr *toop = tk->cast_to_exactness(false)->as_instance_type();
|
const TypeKlassPtr* improved_klass_ptr_type = klass_ptr_type->try_improve();
|
||||||
|
const TypeOopPtr* toop = improved_klass_ptr_type->cast_to_exactness(false)->as_instance_type();
|
||||||
|
|
||||||
// Fast cutout: Check the case that the cast is vacuously true.
|
// Fast cutout: Check the case that the cast is vacuously true.
|
||||||
// This detects the common cases where the test will short-circuit
|
// This detects the common cases where the test will short-circuit
|
||||||
@ -3277,10 +3278,10 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
|||||||
// because if the test is going to turn into zero code, we don't
|
// because if the test is going to turn into zero code, we don't
|
||||||
// want a residual null check left around. (Causes a slowdown,
|
// want a residual null check left around. (Causes a slowdown,
|
||||||
// for example, in some objArray manipulations, such as a[i]=a[j].)
|
// for example, in some objArray manipulations, such as a[i]=a[j].)
|
||||||
if (tk->singleton()) {
|
if (improved_klass_ptr_type->singleton()) {
|
||||||
const TypeOopPtr* objtp = _gvn.type(obj)->isa_oopptr();
|
const TypeOopPtr* objtp = _gvn.type(obj)->isa_oopptr();
|
||||||
if (objtp != nullptr) {
|
if (objtp != nullptr) {
|
||||||
switch (C->static_subtype_check(tk, objtp->as_klass_type())) {
|
switch (C->static_subtype_check(improved_klass_ptr_type, objtp->as_klass_type())) {
|
||||||
case Compile::SSC_always_true:
|
case Compile::SSC_always_true:
|
||||||
// If we know the type check always succeed then we don't use
|
// If we know the type check always succeed then we don't use
|
||||||
// the profiling data at this bytecode. Don't lose it, feed it
|
// the profiling data at this bytecode. Don't lose it, feed it
|
||||||
@ -3346,7 +3347,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Node* cast_obj = nullptr;
|
Node* cast_obj = nullptr;
|
||||||
if (tk->klass_is_exact()) {
|
if (improved_klass_ptr_type->klass_is_exact()) {
|
||||||
// The following optimization tries to statically cast the speculative type of the object
|
// The following optimization tries to statically cast the speculative type of the object
|
||||||
// (for example obtained during profiling) to the type of the superklass and then do a
|
// (for example obtained during profiling) to the type of the superklass and then do a
|
||||||
// dynamic check that the type of the object is what we expect. To work correctly
|
// dynamic check that the type of the object is what we expect. To work correctly
|
||||||
@ -3356,7 +3357,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
|||||||
// a speculative type use it to perform an exact cast.
|
// a speculative type use it to perform an exact cast.
|
||||||
ciKlass* spec_obj_type = obj_type->speculative_type();
|
ciKlass* spec_obj_type = obj_type->speculative_type();
|
||||||
if (spec_obj_type != nullptr || data != nullptr) {
|
if (spec_obj_type != nullptr || data != nullptr) {
|
||||||
cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk, spec_obj_type, safe_for_replace);
|
cast_obj = maybe_cast_profiled_receiver(not_null_obj, improved_klass_ptr_type, spec_obj_type, safe_for_replace);
|
||||||
if (cast_obj != nullptr) {
|
if (cast_obj != nullptr) {
|
||||||
if (failure_control != nullptr) // failure is now impossible
|
if (failure_control != nullptr) // failure is now impossible
|
||||||
(*failure_control) = top();
|
(*failure_control) = top();
|
||||||
@ -3368,7 +3369,11 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
|||||||
|
|
||||||
if (cast_obj == nullptr) {
|
if (cast_obj == nullptr) {
|
||||||
// Generate the subtype check
|
// Generate the subtype check
|
||||||
Node* not_subtype_ctrl = gen_subtype_check(not_null_obj, superklass );
|
Node* improved_superklass = superklass;
|
||||||
|
if (improved_klass_ptr_type != klass_ptr_type && improved_klass_ptr_type->singleton()) {
|
||||||
|
improved_superklass = makecon(improved_klass_ptr_type);
|
||||||
|
}
|
||||||
|
Node* not_subtype_ctrl = gen_subtype_check(not_null_obj, improved_superklass);
|
||||||
|
|
||||||
// Plug in success path into the merge
|
// Plug in success path into the merge
|
||||||
cast_obj = _gvn.transform(new CheckCastPPNode(control(), not_null_obj, toop));
|
cast_obj = _gvn.transform(new CheckCastPPNode(control(), not_null_obj, toop));
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8328480
|
||||||
|
* @summary Test that SubTypeCheckNode takes improved unique concrete klass constant in order to fold consecutive sub
|
||||||
|
* type checks.
|
||||||
|
* @library /test/lib /
|
||||||
|
* @run driver compiler.types.TestSubTypeCheckUniqueSubclass
|
||||||
|
*/
|
||||||
|
|
||||||
|
package compiler.types;
|
||||||
|
|
||||||
|
import compiler.lib.ir_framework.*;
|
||||||
|
|
||||||
|
public class TestSubTypeCheckUniqueSubclass {
|
||||||
|
static Object o = new C(); // Make sure C is loaded.
|
||||||
|
static Object o2 = new C2(); // Make sure C2 is loaded while NeverLoaded is not.
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
TestFramework.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Warmup(0)
|
||||||
|
@IR(counts = {IRNode.SUBTYPE_CHECK, "1"},
|
||||||
|
phase = CompilePhase.ITER_GVN1)
|
||||||
|
static void testAbstractAbstract() {
|
||||||
|
A a = (A)o;
|
||||||
|
A a2 = (B)o;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Warmup(0)
|
||||||
|
@IR(counts = {IRNode.SUBTYPE_CHECK, "1"},
|
||||||
|
phase = CompilePhase.ITER_GVN1)
|
||||||
|
static void testAbstractAbstractWithUnloaded() {
|
||||||
|
A2 a = (A2)o2;
|
||||||
|
A2 a2 = (B2)o2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class A {}
|
||||||
|
abstract class B extends A {}
|
||||||
|
class C extends B {}
|
||||||
|
|
||||||
|
abstract class A2 {}
|
||||||
|
abstract class B2 extends A2 {}
|
||||||
|
class C2 extends B2 {}
|
||||||
|
|
||||||
|
// Class never loaded -> C2 looks like unique sub class.
|
||||||
|
class NeverLoaded extends B2 {}
|
Loading…
Reference in New Issue
Block a user