mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-03 15:08:24 +00:00
8267979: C2: Fix verification code in SubTypeCheckNode::Ideal()
Reviewed-by: neliasso, roland
This commit is contained in:
parent
ae2f37f868
commit
f5634fe39d
@ -103,7 +103,7 @@ const Type* SubTypeCheckNode::sub(const Type* sub_t, const Type* super_t) const
|
||||
return bottom_type();
|
||||
}
|
||||
|
||||
Node *SubTypeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
Node *SubTypeCheckNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node* obj_or_subklass = in(ObjOrSubKlass);
|
||||
Node* superklass = in(SuperKlass);
|
||||
|
||||
@ -134,14 +134,7 @@ Node *SubTypeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
intptr_t con = 0;
|
||||
Node* obj = AddPNode::Ideal_base_and_offset(addr, phase, con);
|
||||
if (con == oopDesc::klass_offset_in_bytes() && obj != NULL) {
|
||||
#ifdef ASSERT
|
||||
const Type* obj_t = phase->type(obj);
|
||||
if (!obj_t->isa_oopptr() && obj_t != Type::TOP) {
|
||||
obj->dump();
|
||||
obj_t->dump(); tty->cr();
|
||||
fatal("only for oop input");
|
||||
}
|
||||
#endif
|
||||
assert(is_oop(phase, obj), "only for oop input");
|
||||
set_req(ObjOrSubKlass, obj);
|
||||
return this;
|
||||
}
|
||||
@ -150,104 +143,111 @@ Node *SubTypeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
// AllocateNode might have more accurate klass input
|
||||
Node* allocated_klass = AllocateNode::Ideal_klass(obj_or_subklass, phase);
|
||||
if (allocated_klass != NULL) {
|
||||
#ifdef ASSERT
|
||||
const Type* obj_or_subklass_t = phase->type(obj_or_subklass);
|
||||
if (!obj_or_subklass_t->isa_oopptr() && obj_or_subklass_t != Type::TOP) {
|
||||
obj_or_subklass->dump();
|
||||
obj_or_subklass_t->dump(); tty->cr();
|
||||
fatal("only for oop input");
|
||||
}
|
||||
#endif
|
||||
assert(is_oop(phase, obj_or_subklass), "only for oop input");
|
||||
set_req(ObjOrSubKlass, allocated_klass);
|
||||
return this;
|
||||
}
|
||||
|
||||
// Verify that optimizing the subtype check to a simple code pattern
|
||||
// when possible would not constant fold better
|
||||
#ifdef ASSERT
|
||||
ciKlass* superk = super_t->is_klassptr()->klass();
|
||||
ciKlass* subk = sub_t->isa_klassptr() ? sub_t->is_klassptr()->klass() : sub_t->is_oopptr()->klass();
|
||||
|
||||
if (super_t->singleton() && subk != NULL && phase->C->static_subtype_check(superk, subk) == Compile::SSC_easy_test) {
|
||||
Node* subklass = NULL;
|
||||
if (sub_t->isa_oopptr()) {
|
||||
Node* adr = phase->transform(new AddPNode(obj_or_subklass, obj_or_subklass, phase->MakeConX(oopDesc::klass_offset_in_bytes())));
|
||||
subklass = phase->transform(LoadKlassNode::make(*phase, NULL, phase->C->immutable_memory(), adr, TypeInstPtr::KLASS));
|
||||
} else {
|
||||
subklass = obj_or_subklass;
|
||||
}
|
||||
Node* res = new CmpPNode(subklass, superklass);
|
||||
Node* cmp = phase->transform(res);
|
||||
const Type* t = phase->type(cmp);
|
||||
if (!((Value(phase) == t) || (t != TypeInt::CC_GT && t != TypeInt::CC_EQ))) {
|
||||
Value(phase)->dump(); tty->cr();
|
||||
t->dump(); tty->cr();
|
||||
obj_or_subklass->dump();
|
||||
subklass->dump();
|
||||
superklass->dump();
|
||||
cmp->dump();
|
||||
tty->print_cr("==============================");
|
||||
phase->C->root()->dump(9999);
|
||||
fatal("missing Value() optimization");
|
||||
}
|
||||
if (phase->is_IterGVN()) {
|
||||
phase->is_IterGVN()->_worklist.push(res);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node *p1 = phase->transform(new AddPNode(superklass, superklass, phase->MakeConX(in_bytes(Klass::super_check_offset_offset()))));
|
||||
Node* m = phase->C->immutable_memory();
|
||||
LoadINode* chk_off_ld = new LoadINode(NULL, m, p1, phase->type(p1)->is_ptr(), TypeInt::INT, MemNode::unordered);
|
||||
Node *chk_off = phase->transform(chk_off_ld);
|
||||
int cacheoff_con = in_bytes(Klass::secondary_super_cache_offset());
|
||||
bool might_be_cache = (phase->find_int_con(chk_off, cacheoff_con) == cacheoff_con);
|
||||
|
||||
if (might_be_cache) {
|
||||
if (phase->is_IterGVN()) {
|
||||
phase->is_IterGVN()->_worklist.push(chk_off_ld);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (super_t->singleton() && subk != NULL && phase->C->static_subtype_check(superk, subk) == Compile::SSC_full_test) {
|
||||
Node* subklass = NULL;
|
||||
if (sub_t->isa_oopptr()) {
|
||||
Node* adr = phase->transform(new AddPNode(obj_or_subklass, obj_or_subklass, phase->MakeConX(oopDesc::klass_offset_in_bytes())));
|
||||
subklass = phase->transform(LoadKlassNode::make(*phase, NULL, phase->C->immutable_memory(), adr, TypeInstPtr::KLASS));
|
||||
} else {
|
||||
subklass = obj_or_subklass;
|
||||
}
|
||||
|
||||
Node *chk_off_X = chk_off;
|
||||
#ifdef _LP64
|
||||
chk_off_X = phase->transform(new ConvI2LNode(chk_off_X));
|
||||
#endif
|
||||
Node *p2 = phase->transform(new AddPNode(subklass,subklass,chk_off_X));
|
||||
Node *kmem = phase->C->immutable_memory();
|
||||
Node *nkls = phase->transform(LoadKlassNode::make(*phase, NULL, kmem, p2, phase->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
|
||||
|
||||
Node* res = new CmpPNode(superklass, nkls);
|
||||
Node* cmp = phase->transform(res);
|
||||
const Type* t = phase->type(cmp);
|
||||
if (!((Value(phase) == t) || (t != TypeInt::CC_GT && t != TypeInt::CC_EQ))) {
|
||||
Value(phase)->dump(); tty->cr();
|
||||
t->dump(); tty->cr();
|
||||
obj_or_subklass->dump();
|
||||
subklass->dump();
|
||||
superklass->dump();
|
||||
nkls->dump();
|
||||
cmp->dump();
|
||||
tty->print_cr("==============================");
|
||||
phase->C->root()->dump(9999);
|
||||
fatal("missing Value() optimization");
|
||||
}
|
||||
if (phase->is_IterGVN()) {
|
||||
phase->is_IterGVN()->_worklist.push(res);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
assert(verify(phase), "missing Value() optimization");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
bool SubTypeCheckNode::is_oop(PhaseGVN* phase, Node* n) {
|
||||
const Type* t = phase->type(n);
|
||||
if (!t->isa_oopptr() && t != Type::TOP) {
|
||||
n->dump();
|
||||
t->dump(); tty->cr();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static Node* record_for_cleanup(Node* n, PhaseGVN* phase) {
|
||||
if (phase->is_IterGVN()) {
|
||||
phase->is_IterGVN()->_worklist.push(n); // record for cleanup
|
||||
}
|
||||
return n;
|
||||
}
|
||||
bool SubTypeCheckNode::verify_helper(PhaseGVN* phase, Node* subklass, const Type* cached_t) {
|
||||
Node* cmp = phase->transform(new CmpPNode(subklass, in(SuperKlass)));
|
||||
record_for_cleanup(cmp, phase);
|
||||
|
||||
const Type* cmp_t = phase->type(cmp);
|
||||
const Type* t = Value(phase);
|
||||
|
||||
if (t == cmp_t ||
|
||||
t != cached_t || // previous observations don't hold anymore
|
||||
(cmp_t != TypeInt::CC_GT && cmp_t != TypeInt::CC_EQ)) {
|
||||
return true;
|
||||
} else {
|
||||
t->dump(); tty->cr();
|
||||
this->dump(2); tty->cr();
|
||||
cmp_t->dump(); tty->cr();
|
||||
subklass->dump(2); tty->cr();
|
||||
tty->print_cr("==============================");
|
||||
phase->C->root()->dump(9999);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that optimizing the subtype check to a simple code pattern when possible would not constant fold better.
|
||||
bool SubTypeCheckNode::verify(PhaseGVN* phase) {
|
||||
Compile* C = phase->C;
|
||||
Node* obj_or_subklass = in(ObjOrSubKlass);
|
||||
Node* superklass = in(SuperKlass);
|
||||
|
||||
const Type* sub_t = phase->type(obj_or_subklass);
|
||||
const Type* super_t = phase->type(superklass);
|
||||
|
||||
ciKlass* subk = sub_t->isa_klassptr() ? sub_t->is_klassptr()->klass() : sub_t->is_oopptr()->klass(); // can be NULL for bottom[]
|
||||
ciKlass* superk = super_t->is_klassptr()->klass();
|
||||
|
||||
if (super_t->singleton() && subk != NULL) {
|
||||
Node* subklass = NULL;
|
||||
if (sub_t->isa_oopptr()) {
|
||||
Node* adr = phase->transform(new AddPNode(obj_or_subklass, obj_or_subklass, phase->MakeConX(oopDesc::klass_offset_in_bytes())));
|
||||
subklass = phase->transform(LoadKlassNode::make(*phase, NULL, C->immutable_memory(), adr, TypeInstPtr::KLASS));
|
||||
record_for_cleanup(subklass, phase);
|
||||
} else {
|
||||
subklass = obj_or_subklass;
|
||||
}
|
||||
|
||||
const Type* cached_t = Value(phase); // cache the type to validate consistency
|
||||
switch (C->static_subtype_check(superk, subk)) {
|
||||
case Compile::SSC_easy_test: {
|
||||
return verify_helper(phase, subklass, cached_t);
|
||||
}
|
||||
case Compile::SSC_full_test: {
|
||||
Node* p1 = phase->transform(new AddPNode(superklass, superklass, phase->MakeConX(in_bytes(Klass::super_check_offset_offset()))));
|
||||
Node* chk_off = phase->transform(new LoadINode(NULL, C->immutable_memory(), p1, phase->type(p1)->is_ptr(), TypeInt::INT, MemNode::unordered));
|
||||
record_for_cleanup(chk_off, phase);
|
||||
|
||||
int cacheoff_con = in_bytes(Klass::secondary_super_cache_offset());
|
||||
bool might_be_cache = (phase->find_int_con(chk_off, cacheoff_con) == cacheoff_con);
|
||||
if (!might_be_cache) {
|
||||
Node* chk_off_X = chk_off;
|
||||
#ifdef _LP64
|
||||
chk_off_X = phase->transform(new ConvI2LNode(chk_off_X));
|
||||
#endif
|
||||
Node* p2 = phase->transform(new AddPNode(subklass, subklass, chk_off_X));
|
||||
Node* nkls = phase->transform(LoadKlassNode::make(*phase, NULL, C->immutable_memory(), p2, phase->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
|
||||
|
||||
return verify_helper(phase, nkls, cached_t);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Compile::SSC_always_false:
|
||||
case Compile::SSC_always_true:
|
||||
default: {
|
||||
break; // nothing to do
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -49,6 +49,14 @@ public:
|
||||
virtual int Opcode() const;
|
||||
const Type* bottom_type() const { return TypeInt::CC; }
|
||||
bool depends_only_on_test() const { return false; };
|
||||
|
||||
#ifdef ASSERT
|
||||
private:
|
||||
bool verify(PhaseGVN* phase);
|
||||
bool verify_helper(PhaseGVN* phase, Node* subklass, const Type* cached_t);
|
||||
|
||||
static bool is_oop(PhaseGVN* phase, Node* n);
|
||||
#endif // ASSERT
|
||||
};
|
||||
|
||||
#endif // SHARE_OPTO_SUBTYPENODE_HPP
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user