Skip to content

Commit

Permalink
8328480: C2: SubTypeCheckNode in checkcast should use the klass const…
Browse files Browse the repository at this point in the history
…ant of a unique concrete sub class
  • Loading branch information
chhagedorn committed Mar 27, 2024
1 parent af15c68 commit 26a717d
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 7 deletions.
19 changes: 12 additions & 7 deletions src/hotspot/share/opto/graphKit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3257,19 +3257,20 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac
Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
Node* *failure_control) {
kill_dead_locals(); // Benefit all the uncommon traps
const TypeKlassPtr *tk = _gvn.type(superklass)->is_klassptr()->try_improve();
const TypeOopPtr *toop = tk->cast_to_exactness(false)->as_instance_type();
const TypeKlassPtr* klass_ptr_type = _gvn.type(superklass)->is_klassptr();
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.
// This detects the common cases where the test will short-circuit
// away completely. We do this before we perform the null check,
// because if the test is going to turn into zero code, we don't
// want a residual null check left around. (Causes a slowdown,
// 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();
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:
// 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
Expand Down Expand Up @@ -3335,7 +3336,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
}

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
// (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
Expand All @@ -3345,7 +3346,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
// a speculative type use it to perform an exact cast.
ciKlass* spec_obj_type = obj_type->speculative_type();
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 (failure_control != nullptr) // failure is now impossible
(*failure_control) = top();
Expand All @@ -3357,7 +3358,11 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,

if (cast_obj == nullptr) {
// 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
cast_obj = _gvn.transform(new CheckCastPPNode(control(), not_null_obj, toop));
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {}

0 comments on commit 26a717d

Please sign in to comment.