Skip to content
Permalink
Browse files

8238691: C2: turn subtype check into macro node

Reviewed-by: vlivanov, thartmann
  • Loading branch information
rwestrel committed Feb 14, 2020
1 parent e4b27a4 commit 52d46c314b0f9b46544695609d063ac89bcd5dd7
@@ -746,6 +746,9 @@
range(0, max_juint) \
\
product(bool, UseProfiledLoopPredicate, true, \
"move predicates out of loops based on profiling data") \
"Move predicates out of loops based on profiling data") \
\
diagnostic(bool, ExpandSubTypeCheckAtParseTime, false, \
"Do not use subtype check macro node") \

#endif // SHARE_OPTO_C2_GLOBALS_HPP
@@ -46,6 +46,7 @@
#include "opto/opaquenode.hpp"
#include "opto/rootnode.hpp"
#include "opto/subnode.hpp"
#include "opto/subtypenode.hpp"
#include "opto/vectornode.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_SHENANDOAHGC
@@ -250,6 +250,7 @@ macro(OverflowMulL)
macro(PCTable)
macro(Parm)
macro(PartialSubtypeCheck)
macro(SubTypeCheck)
macro(Phi)
macro(PopCountI)
macro(PopCountL)
@@ -4239,6 +4239,9 @@ int Compile::static_subtype_check(ciKlass* superk, ciKlass* subk) {
// Add a dependency if there is a chance of a later subclass.
dependencies()->assert_leaf_type(ik);
}
if (ik->is_abstract()) {
return SSC_always_false;
}
return SSC_easy_test; // (3) caller can do a simple ptr comparison
}
} else {
@@ -3199,6 +3199,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives ||
op == Op_StrCompressedCopy || op == Op_StrInflatedCopy ||
op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar ||
op == Op_SubTypeCheck ||
BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use))) {
n->dump();
use->dump();

Large diffs are not rendered by default.

@@ -825,13 +825,7 @@ class GraphKit : public Phase {
Node* gen_checkcast( Node *subobj, Node* superkls,
Node* *failure_control = NULL );

Node* gen_subtype_check(Node* subklass, Node* superklass) {
MergeMemNode* mem = merged_memory();
Node* ctrl = control();
Node* n = Phase::gen_subtype_check(subklass, superklass, &ctrl, mem, &_gvn);
set_control(ctrl);
return n;
}
Node* gen_subtype_check(Node* obj, Node* superklass);

// Exact type check used for predicted calls and casts.
// Rewrites (*casted_receiver) to be casted to the stronger type.
@@ -3699,8 +3699,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) {
// Reason_class_check rather than Reason_intrinsic because we
// want to intrinsify even if this traps.
if (!too_many_traps(Deoptimization::Reason_class_check)) {
Node* not_subtype_ctrl = gen_subtype_check(load_object_klass(original),
klass_node);
Node* not_subtype_ctrl = gen_subtype_check(original, klass_node);

if (not_subtype_ctrl != top()) {
PreserveJVMState pjvms(this);
@@ -4766,16 +4765,17 @@ bool LibraryCallKit::inline_arraycopy() {
}

// (9) each element of an oop array must be assignable
Node* src_klass = load_object_klass(src);
Node* dest_klass = load_object_klass(dest);
Node* not_subtype_ctrl = gen_subtype_check(src_klass, dest_klass);
if (src != dest) {
Node* not_subtype_ctrl = gen_subtype_check(src, dest_klass);

if (not_subtype_ctrl != top()) {
PreserveJVMState pjvms(this);
set_control(not_subtype_ctrl);
uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_make_not_entrant);
assert(stopped(), "Should be stopped");
if (not_subtype_ctrl != top()) {
PreserveJVMState pjvms(this);
set_control(not_subtype_ctrl);
uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_make_not_entrant);
assert(stopped(), "Should be stopped");
}
}
{
PreserveJVMState pjvms(this);
@@ -4089,7 +4089,7 @@ Node *PhaseIdealLoop::get_late_ctrl( Node *n, Node *early ) {
}
} else {
Node *sctrl = has_ctrl(s) ? get_ctrl(s) : s->in(0);
assert(sctrl != NULL || s->outcnt() == 0, "must have control");
assert(sctrl != NULL || !s->is_reachable_from_root(), "must have control");
if (sctrl != NULL && !sctrl->is_top() && C->can_alias(s->adr_type(), load_alias_idx) && is_dominator(early, sctrl)) {
LCA = dom_lca_for_get_late_ctrl(LCA, sctrl, n);
}
@@ -40,6 +40,7 @@
#include "opto/opaquenode.hpp"
#include "opto/rootnode.hpp"
#include "opto/subnode.hpp"
#include "opto/subtypenode.hpp"
#include "utilities/macros.hpp"

//=============================================================================
@@ -656,6 +657,9 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) {
}
assert(bol->Opcode() == Op_Bool, "Unexpected node");
int cmp_op = bol->in(1)->Opcode();
if (cmp_op == Op_SubTypeCheck) { // SubTypeCheck expansion expects an IfNode
return NULL;
}
// It is expensive to generate flags from a float compare.
// Avoid duplicated float compare.
if (phis > 1 && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) return NULL;
@@ -35,6 +35,7 @@
#include "opto/compile.hpp"
#include "opto/convertnode.hpp"
#include "opto/graphKit.hpp"
#include "opto/intrinsicnode.hpp"
#include "opto/locknode.hpp"
#include "opto/loopnode.hpp"
#include "opto/macro.hpp"
@@ -46,6 +47,7 @@
#include "opto/rootnode.hpp"
#include "opto/runtime.hpp"
#include "opto/subnode.hpp"
#include "opto/subtypenode.hpp"
#include "opto/type.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/macros.hpp"
@@ -2533,6 +2535,43 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) {
_igvn.replace_node(_memproj_fallthrough, mem_phi);
}

void PhaseMacroExpand::expand_subtypecheck_node(SubTypeCheckNode *check) {
assert(check->in(SubTypeCheckNode::Control) == NULL, "should be pinned");
Node* bol = check->unique_out();
Node* obj_or_subklass = check->in(SubTypeCheckNode::ObjOrSubKlass);
Node* superklass = check->in(SubTypeCheckNode::SuperKlass);
assert(bol->is_Bool() && bol->as_Bool()->_test._test == BoolTest::ne, "unexpected bool node");

for (DUIterator_Last imin, i = bol->last_outs(imin); i >= imin; --i) {
Node* iff = bol->last_out(i);
assert(iff->is_If(), "where's the if?");

if (iff->in(0)->is_top()) {
_igvn.replace_input_of(iff, 1, C->top());
continue;
}

Node* iftrue = iff->as_If()->proj_out(1);
Node* iffalse = iff->as_If()->proj_out(0);
Node* ctrl = iff->in(0);

Node* subklass = NULL;
if (_igvn.type(obj_or_subklass)->isa_klassptr()) {
subklass = obj_or_subklass;
} else {
Node* k_adr = basic_plus_adr(obj_or_subklass, oopDesc::klass_offset_in_bytes());
subklass = _igvn.transform(LoadKlassNode::make(_igvn, NULL, C->immutable_memory(), k_adr, TypeInstPtr::KLASS));
}

Node* not_subtype_ctrl = Phase::gen_subtype_check(subklass, superklass, &ctrl, NULL, _igvn);

_igvn.replace_input_of(iff, 0, C->top());
_igvn.replace_node(iftrue, not_subtype_ctrl);
_igvn.replace_node(iffalse, ctrl);
}
_igvn.replace_node(check, C->top());
}

//---------------------------eliminate_macro_nodes----------------------
// Eliminate scalar replaced allocations and associated locks.
void PhaseMacroExpand::eliminate_macro_nodes() {
@@ -2589,6 +2628,8 @@ void PhaseMacroExpand::eliminate_macro_nodes() {
break;
case Node::Class_OuterStripMinedLoop:
break;
case Node::Class_SubTypeCheck:
break;
default:
assert(n->Opcode() == Op_LoopLimit ||
n->Opcode() == Op_Opaque1 ||
@@ -2695,6 +2736,10 @@ bool PhaseMacroExpand::expand_macro_nodes() {
expand_arraycopy_node(n->as_ArrayCopy());
assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list");
break;
case Node::Class_SubTypeCheck:
expand_subtypecheck_node(n->as_SubTypeCheck());
assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list");
break;
}
if (C->failing()) return true;
}
@@ -30,6 +30,7 @@
class AllocateNode;
class AllocateArrayNode;
class CallNode;
class SubTypeCheckNode;
class Node;
class PhaseIterGVN;

@@ -183,6 +184,8 @@ class PhaseMacroExpand : public Phase {

void expand_arraycopy_node(ArrayCopyNode *ac);

void expand_subtypecheck_node(SubTypeCheckNode *check);

int replace_input(Node *use, Node *oldref, Node *newref);
void migrate_outs(Node *old, Node *target);
void copy_call_debug_info(CallNode *oldcall, CallNode * newcall);
@@ -524,7 +524,7 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode*
// Test S[] against D[], not S against D, because (probably)
// the secondary supertype cache is less busy for S[] than S.
// This usually only matters when D is an interface.
Node* not_subtype_ctrl = Phase::gen_subtype_check(src_klass, dest_klass, ctrl, mem, &_igvn);
Node* not_subtype_ctrl = Phase::gen_subtype_check(src_klass, dest_klass, ctrl, mem, _igvn);
// Plug failing path into checked_oop_disjoint_arraycopy
if (not_subtype_ctrl != top()) {
Node* local_ctrl = not_subtype_ctrl;
@@ -146,6 +146,7 @@ class StartNode;
class State;
class StoreNode;
class SubNode;
class SubTypeCheckNode;
class Type;
class TypeNode;
class UnlockNode;
@@ -706,6 +707,7 @@ class Node {
DEFINE_CLASS_ID(Cmp, Sub, 0)
DEFINE_CLASS_ID(FastLock, Cmp, 0)
DEFINE_CLASS_ID(FastUnlock, Cmp, 1)
DEFINE_CLASS_ID(SubTypeCheck,Cmp, 2)

DEFINE_CLASS_ID(MergeMem, Node, 7)
DEFINE_CLASS_ID(Bool, Node, 8)
@@ -875,6 +877,7 @@ class Node {
DEFINE_CLASS_QUERY(Start)
DEFINE_CLASS_QUERY(Store)
DEFINE_CLASS_QUERY(Sub)
DEFINE_CLASS_QUERY(SubTypeCheck)
DEFINE_CLASS_QUERY(Type)
DEFINE_CLASS_QUERY(Vector)
DEFINE_CLASS_QUERY(LoadVector)
@@ -132,7 +132,7 @@ class Phase : public StackObj {
// Object; if you wish to check an Object you need to load the Object's
// class prior to coming here.
// Used in GraphKit and PhaseMacroExpand
static Node* gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, MergeMemNode* mem, PhaseGVN* gvn);
static Node* gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, Node* mem, PhaseGVN& gvn);

public:
Compile * C;
@@ -1352,7 +1352,7 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) {
Node *cmp = in(1);
if( !cmp->is_Sub() ) return NULL;
int cop = cmp->Opcode();
if( cop == Op_FastLock || cop == Op_FastUnlock) return NULL;
if( cop == Op_FastLock || cop == Op_FastUnlock || cmp->is_SubTypeCheck()) return NULL;
Node *cmp1 = cmp->in(1);
Node *cmp2 = cmp->in(2);
if( !cmp1 ) return NULL;

0 comments on commit 52d46c3

Please sign in to comment.