8297933: [REDO] Compiler should only use verified interface types for optimization

Reviewed-by: kvn, vlivanov
This commit is contained in:
Roland Westrelin 2023-01-09 08:26:08 +00:00
parent 9b1ade8e2b
commit 05a0a71031
25 changed files with 1185 additions and 893 deletions

View File

@ -26,7 +26,8 @@
#include "ci/ciArrayKlass.hpp"
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciTypeArrayKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "ci/ciUtilities.inline.hpp"
#include "memory/universe.hpp"
// ciArrayKlass
//
@ -103,3 +104,4 @@ ciArrayKlass* ciArrayKlass::make(ciType* element_type) {
return ciObjArrayKlass::make(element_type->as_klass());
}
}

View File

@ -69,6 +69,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
_has_injected_fields = -1;
_implementor = NULL; // we will fill these lazily
_transitive_interfaces = NULL;
// Ensure that the metadata wrapped by the ciMetadata is kept alive by GC.
// This is primarily useful for metadata which is considered as weak roots
@ -729,6 +730,32 @@ void ciInstanceKlass::dump_replay_instanceKlass(outputStream* out, InstanceKlass
}
}
GrowableArray<ciInstanceKlass*>* ciInstanceKlass::transitive_interfaces() const{
if (_transitive_interfaces == NULL) {
const_cast<ciInstanceKlass*>(this)->compute_transitive_interfaces();
}
return _transitive_interfaces;
}
void ciInstanceKlass::compute_transitive_interfaces() {
GUARDED_VM_ENTRY(
InstanceKlass* ik = get_instanceKlass();
Array<InstanceKlass*>* interfaces = ik->transitive_interfaces();
int orig_length = interfaces->length();
Arena* arena = CURRENT_ENV->arena();
int transitive_interfaces_len = orig_length + (is_interface() ? 1 : 0);
GrowableArray<ciInstanceKlass*>* transitive_interfaces = new(arena)GrowableArray<ciInstanceKlass*>(arena, transitive_interfaces_len,
0, NULL);
for (int i = 0; i < orig_length; i++) {
transitive_interfaces->append(CURRENT_ENV->get_instance_klass(interfaces->at(i)));
}
if (is_interface()) {
transitive_interfaces->append(this);
}
_transitive_interfaces = transitive_interfaces;
);
}
void ciInstanceKlass::dump_replay_data(outputStream* out) {
ResourceMark rm;

View File

@ -76,9 +76,11 @@ private:
// A ciInstanceKlass that's not itself: one implementor.
// Itself: more than one implementor.
ciInstanceKlass* _implementor;
GrowableArray<ciInstanceKlass*>* _transitive_interfaces;
void compute_injected_fields();
bool compute_injected_fields_helper();
void compute_transitive_interfaces();
protected:
ciInstanceKlass(Klass* k);
@ -292,6 +294,7 @@ public:
bool has_trusted_loader() const {
return _has_trusted_loader;
}
GrowableArray<ciInstanceKlass*>* transitive_interfaces() const;
// Replay support

View File

@ -167,6 +167,7 @@ void ciObjectFactory::init_shared_objects() {
assert (obj->is_metadata(), "what else would it be?");
if (obj->is_loaded() && obj->is_instance_klass()) {
obj->as_instance_klass()->compute_nonstatic_fields();
obj->as_instance_klass()->transitive_interfaces();
}
}
}

View File

@ -307,7 +307,13 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape,
return false;
}
Node* hook = new Node(1);
hook->init_req(0, dest_offset);
Node* src_scale = phase->transform(new LShiftXNode(src_offset, phase->intcon(shift)));
hook->destruct(phase);
Node* dest_scale = phase->transform(new LShiftXNode(dest_offset, phase->intcon(shift)));
adr_src = phase->transform(new AddPNode(base_src, base_src, src_scale));

View File

@ -371,30 +371,6 @@ Node* CastLLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
return optimize_integer_cast(phase, T_LONG);
}
//=============================================================================
//------------------------------Identity---------------------------------------
// If input is already higher or equal to cast type, then this is an identity.
Node* CheckCastPPNode::Identity(PhaseGVN* phase) {
Node* dom = dominating_cast(phase, phase);
if (dom != NULL) {
return dom;
}
if (_dependency != RegularDependency) {
return this;
}
const Type* t = phase->type(in(1));
if (EnableVectorReboxing && in(1)->Opcode() == Op_VectorBox) {
if (t->higher_equal_speculative(phase->type(this))) {
return in(1);
}
} else if (t == phase->type(this)) {
// Toned down to rescue meeting at a Phi 3 different oops all implementing
// the same interface.
return in(1);
}
return this;
}
//------------------------------Value------------------------------------------
// Take 'join' of input and cast-up type, unless working with an Interface
const Type* CheckCastPPNode::Value(PhaseGVN* phase) const {
@ -403,83 +379,23 @@ const Type* CheckCastPPNode::Value(PhaseGVN* phase) const {
const Type *inn = phase->type(in(1));
if( inn == Type::TOP ) return Type::TOP; // No information yet
const TypePtr *in_type = inn->isa_ptr();
const TypePtr *my_type = _type->isa_ptr();
if (inn->isa_oopptr() && _type->isa_oopptr()) {
return ConstraintCastNode::Value(phase);
}
const TypePtr *in_type = inn->isa_ptr();
const TypePtr *my_type = _type->isa_ptr();
const Type *result = _type;
if( in_type != NULL && my_type != NULL ) {
TypePtr::PTR in_ptr = in_type->ptr();
if (in_type != NULL && my_type != NULL) {
TypePtr::PTR in_ptr = in_type->ptr();
if (in_ptr == TypePtr::Null) {
result = in_type;
} else if (in_ptr == TypePtr::Constant) {
if (my_type->isa_rawptr()) {
result = my_type;
} else {
const TypeOopPtr *jptr = my_type->isa_oopptr();
assert(jptr, "");
result = !in_type->higher_equal(_type)
? my_type->cast_to_ptr_type(TypePtr::NotNull)
: in_type;
}
} else {
result = my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) );
} else if (in_ptr != TypePtr::Constant) {
result = my_type->cast_to_ptr_type(my_type->join_ptr(in_ptr));
}
}
// This is the code from TypePtr::xmeet() that prevents us from
// having 2 ways to represent the same type. We have to replicate it
// here because we don't go through meet/join.
if (result->remove_speculative() == result->speculative()) {
result = result->remove_speculative();
}
// Same as above: because we don't go through meet/join, remove the
// speculative type if we know we won't use it.
return result->cleanup_speculative();
// JOIN NOT DONE HERE BECAUSE OF INTERFACE ISSUES.
// FIX THIS (DO THE JOIN) WHEN UNION TYPES APPEAR!
//
// Remove this code after overnight run indicates no performance
// loss from not performing JOIN at CheckCastPPNode
//
// const TypeInstPtr *in_oop = in->isa_instptr();
// const TypeInstPtr *my_oop = _type->isa_instptr();
// // If either input is an 'interface', return destination type
// assert (in_oop == NULL || in_oop->klass() != NULL, "");
// assert (my_oop == NULL || my_oop->klass() != NULL, "");
// if( (in_oop && in_oop->klass()->is_interface())
// ||(my_oop && my_oop->klass()->is_interface()) ) {
// TypePtr::PTR in_ptr = in->isa_ptr() ? in->is_ptr()->_ptr : TypePtr::BotPTR;
// // Preserve cast away nullness for interfaces
// if( in_ptr == TypePtr::NotNull && my_oop && my_oop->_ptr == TypePtr::BotPTR ) {
// return my_oop->cast_to_ptr_type(TypePtr::NotNull);
// }
// return _type;
// }
//
// // Neither the input nor the destination type is an interface,
//
// // history: JOIN used to cause weird corner case bugs
// // return (in == TypeOopPtr::NULL_PTR) ? in : _type;
// // JOIN picks up NotNull in common instance-of/check-cast idioms, both oops.
// // JOIN does not preserve NotNull in other cases, e.g. RawPtr vs InstPtr
// const Type *join = in->join(_type);
// // Check if join preserved NotNull'ness for pointers
// if( join->isa_ptr() && _type->isa_ptr() ) {
// TypePtr::PTR join_ptr = join->is_ptr()->_ptr;
// TypePtr::PTR type_ptr = _type->is_ptr()->_ptr;
// // If there isn't any NotNull'ness to preserve
// // OR if join preserved NotNull'ness then return it
// if( type_ptr == TypePtr::BotPTR || type_ptr == TypePtr::Null ||
// join_ptr == TypePtr::NotNull || join_ptr == TypePtr::Constant ) {
// return join;
// }
// // ELSE return same old type as before
// return _type;
// }
// // Not joining two pointers
// return join;
return result;
}
//=============================================================================

View File

@ -179,7 +179,6 @@ class CheckCastPPNode: public ConstraintCastNode {
init_req(0, c);
}
virtual Node* Identity(PhaseGVN* phase);
virtual const Type* Value(PhaseGVN* phase) const;
virtual int Opcode() const;
virtual uint ideal_reg() const { return Op_RegP; }

View File

@ -1214,42 +1214,12 @@ const Type* PhiNode::Value(PhaseGVN* phase) const {
}
}
// Until we have harmony between classes and interfaces in the type
// lattice, we must tread carefully around phis which implicitly
// convert the one to the other.
const TypePtr* ttp = _type->make_ptr();
const TypeInstPtr* ttip = (ttp != NULL) ? ttp->isa_instptr() : NULL;
const TypeInstKlassPtr* ttkp = (ttp != NULL) ? ttp->isa_instklassptr() : NULL;
bool is_intf = false;
if (ttip != NULL) {
if (ttip->is_interface())
is_intf = true;
}
if (ttkp != NULL) {
if (ttkp->is_interface())
is_intf = true;
}
// Default case: merge all inputs
const Type *t = Type::TOP; // Merged type starting value
for (uint i = 1; i < req(); ++i) {// For all paths in
// Reachable control path?
if (r->in(i) && phase->type(r->in(i)) == Type::CONTROL) {
const Type* ti = phase->type(in(i));
// We assume that each input of an interface-valued Phi is a true
// subtype of that interface. This might not be true of the meet
// of all the input types. The lattice is not distributive in
// such cases. Ward off asserts in type.cpp by refusing to do
// meets between interfaces and proper classes.
const TypePtr* tip = ti->make_ptr();
const TypeInstPtr* tiip = (tip != NULL) ? tip->isa_instptr() : NULL;
if (tiip) {
bool ti_is_intf = false;
if (tiip->is_interface())
ti_is_intf = true;
if (is_intf != ti_is_intf)
{ t = _type; break; }
}
t = t->meet_speculative(ti);
}
}
@ -1273,60 +1243,13 @@ const Type* PhiNode::Value(PhaseGVN* phase) const {
// The following logic has been moved into TypeOopPtr::filter.
const Type* jt = t->join_speculative(_type);
if (jt->empty()) { // Emptied out???
// Check for evil case of 't' being a class and '_type' expecting an
// interface. This can happen because the bytecodes do not contain
// enough type info to distinguish a Java-level interface variable
// from a Java-level object variable. If we meet 2 classes which
// both implement interface I, but their meet is at 'j/l/O' which
// doesn't implement I, we have no way to tell if the result should
// be 'I' or 'j/l/O'. Thus we'll pick 'j/l/O'. If this then flows
// into a Phi which "knows" it's an Interface type we'll have to
// uplift the type.
if (!t->empty() && ttip && ttip->is_interface()) {
assert(ft == _type, ""); // Uplift to interface
} else if (!t->empty() && ttkp && ttkp->is_interface()) {
assert(ft == _type, ""); // Uplift to interface
} else {
// We also have to handle 'evil cases' of interface- vs. class-arrays
Type::get_arrays_base_elements(jt, _type, NULL, &ttip);
if (!t->empty() && ttip != NULL && ttip->is_interface()) {
assert(ft == _type, ""); // Uplift to array of interface
} else {
// Otherwise it's something stupid like non-overlapping int ranges
// found on dying counted loops.
assert(ft == Type::TOP, ""); // Canonical empty value
}
}
// Otherwise it's something stupid like non-overlapping int ranges
// found on dying counted loops.
assert(ft == Type::TOP, ""); // Canonical empty value
}
else {
// If we have an interface-typed Phi and we narrow to a class type, the join
// should report back the class. However, if we have a J/L/Object
// class-typed Phi and an interface flows in, it's possible that the meet &
// join report an interface back out. This isn't possible but happens
// because the type system doesn't interact well with interfaces.
const TypePtr *jtp = jt->make_ptr();
const TypeInstPtr *jtip = (jtp != NULL) ? jtp->isa_instptr() : NULL;
const TypeInstKlassPtr *jtkp = (jtp != NULL) ? jtp->isa_instklassptr() : NULL;
if (jtip && ttip) {
if (jtip->is_interface() &&
!ttip->is_interface()) {
assert(ft == ttip->cast_to_ptr_type(jtip->ptr()) ||
ft->isa_narrowoop() && ft->make_ptr() == ttip->cast_to_ptr_type(jtip->ptr()), "");
jt = ft;
}
}
if (jtkp && ttkp) {
if (jtkp->is_interface() &&
!jtkp->klass_is_exact() && // Keep exact interface klass (6894807)
ttkp->is_loaded() && !ttkp->is_interface()) {
assert(ft == ttkp->cast_to_ptr_type(jtkp->ptr()) ||
ft->isa_narrowklass() && ft->make_ptr() == ttkp->cast_to_ptr_type(jtkp->ptr()), "");
jt = ft;
}
}
if (jt != ft && jt->base() == ft->base()) {
if (jt->isa_int() &&
jt->is_int()->_lo == ft->is_int()->_lo &&

View File

@ -4360,8 +4360,8 @@ Compile::TracePhase::~TracePhase() {
// (1) subklass is already limited to a subtype of superklass => always ok
// (2) subklass does not overlap with superklass => always fail
// (3) superklass has NO subtypes and we can check with a simple compare.
Compile::SubTypeCheckResult Compile::static_subtype_check(const TypeKlassPtr* superk, const TypeKlassPtr* subk) {
if (StressReflectiveCode) {
Compile::SubTypeCheckResult Compile::static_subtype_check(const TypeKlassPtr* superk, const TypeKlassPtr* subk, bool skip) {
if (skip) {
return SSC_full_test; // Let caller generate the general case.
}

View File

@ -1174,7 +1174,7 @@ class Compile : public Phase {
// Static parse-time type checking logic for gen_subtype_check:
enum SubTypeCheckResult { SSC_always_false, SSC_always_true, SSC_easy_test, SSC_full_test };
SubTypeCheckResult static_subtype_check(const TypeKlassPtr* superk, const TypeKlassPtr* subk);
SubTypeCheckResult static_subtype_check(const TypeKlassPtr* superk, const TypeKlassPtr* subk, bool skip = StressReflectiveCode);
static Node* conv_I2X_index(PhaseGVN* phase, Node* offset, const TypeInt* sizetype,
// Optional control dependency (for example, on range check)

View File

@ -597,7 +597,7 @@ void Parse::do_call() {
if (receiver_constraint != NULL) {
Node* receiver_node = stack(sp() - nargs);
Node* cls_node = makecon(TypeKlassPtr::make(receiver_constraint));
Node* cls_node = makecon(TypeKlassPtr::make(receiver_constraint, Type::trust_interfaces));
Node* bad_type_ctrl = NULL;
Node* casted_receiver = gen_checkcast(receiver_node, cls_node, &bad_type_ctrl);
if (bad_type_ctrl != NULL) {

View File

@ -2182,7 +2182,7 @@ Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls, Prof
// Should the klass from the profile be recorded in the speculative type?
if (current_type->would_improve_type(exact_kls, jvms()->depth())) {
const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls);
const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls, Type::trust_interfaces);
const TypeOopPtr* xtype = tklass->as_instance_type();
assert(xtype->klass_is_exact(), "Should be exact");
// Any reason to believe n is not null (from this profiling or a previous one)?
@ -2636,7 +2636,7 @@ static IfNode* gen_subtype_check_compare(Node* ctrl, Node* in1, Node* in2, BoolT
case T_ADDRESS: cmp = new CmpPNode(in1, in2); break;
default: fatal("unexpected comparison type %s", type2name(bt));
}
gvn.transform(cmp);
cmp = gvn.transform(cmp);
Node* bol = gvn.transform(new BoolNode(cmp, test));
IfNode* iff = new IfNode(ctrl, bol, p, COUNT_UNKNOWN);
gvn.transform(iff);
@ -2844,7 +2844,7 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass,
Node* *casted_receiver) {
assert(!klass->is_interface(), "no exact type check on interfaces");
const TypeKlassPtr* tklass = TypeKlassPtr::make(klass);
const TypeKlassPtr* tklass = TypeKlassPtr::make(klass, Type::trust_interfaces);
Node* recv_klass = load_object_klass(receiver);
Node* want_klass = makecon(tklass);
Node* cmp = _gvn.transform(new CmpPNode(recv_klass, want_klass));
@ -2873,7 +2873,7 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass,
//------------------------------subtype_check_receiver-------------------------
Node* GraphKit::subtype_check_receiver(Node* receiver, ciKlass* klass,
Node** casted_receiver) {
const TypeKlassPtr* tklass = TypeKlassPtr::make(klass);
const TypeKlassPtr* tklass = TypeKlassPtr::make(klass, Type::trust_interfaces)->try_improve();
Node* want_klass = makecon(tklass);
Node* slow_ctl = gen_subtype_check(receiver, want_klass);
@ -2996,7 +2996,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
ciKlass* exact_kls = spec_klass == NULL ? profile_has_unique_klass() : spec_klass;
if (exact_kls != NULL) {// no cast failures here
if (require_klass == NULL ||
C->static_subtype_check(require_klass, TypeKlassPtr::make(exact_kls)) == Compile::SSC_always_true) {
C->static_subtype_check(require_klass, TypeKlassPtr::make(exact_kls, Type::trust_interfaces)) == Compile::SSC_always_true) {
// If we narrow the type to match what the type profile sees or
// the speculative type, we can then remove the rest of the
// cast.
@ -3182,8 +3182,8 @@ 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();
const Type *toop = tk->cast_to_exactness(false)->as_instance_type();
const TypeKlassPtr *tk = _gvn.type(superklass)->is_klassptr()->try_improve();
const TypeOopPtr *toop = tk->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

View File

@ -500,9 +500,7 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) {
if (t != NULL && (t->isa_instptr() || t->isa_instklassptr())) {
const TypeInstPtr *toop = t->isa_instptr();
const TypeInstKlassPtr *tkls = t->isa_instklassptr();
if ((toop != NULL && toop->is_interface()) || (tkls != NULL && tkls->is_interface())) {
s2.print(" Interface:");
} else if (toop) {
if (toop) {
s2.print(" Oop:");
} else if (tkls) {
s2.print(" Klass:");

View File

@ -3667,7 +3667,7 @@ bool LibraryCallKit::inline_Class_cast() {
// Don't use intrinsic when class is not loaded.
return false;
} else {
int static_res = C->static_subtype_check(TypeKlassPtr::make(tm->as_klass()), tp->as_klass_type());
int static_res = C->static_subtype_check(TypeKlassPtr::make(tm->as_klass(), Type::trust_interfaces), tp->as_klass_type());
if (static_res == Compile::SSC_always_true) {
// isInstance() is true - fold the code.
set_result(obj);
@ -7235,7 +7235,7 @@ bool LibraryCallKit::inline_digestBase_implCompressMB(Node* digestBase_obj, ciIn
BasicType elem_type, address stubAddr, const char *stubName,
Node* src_start, Node* ofs, Node* limit) {
const TypeKlassPtr* aklass = TypeKlassPtr::make(instklass_digestBase);
const TypeOopPtr* xtype = aklass->as_instance_type()->cast_to_ptr_type(TypePtr::NotNull);
const TypeOopPtr* xtype = aklass->cast_to_exactness(false)->as_instance_type()->cast_to_ptr_type(TypePtr::NotNull);
Node* digest_obj = new CheckCastPPNode(control(), digestBase_obj, xtype);
digest_obj = _gvn.transform(digest_obj);

View File

@ -2027,7 +2027,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const {
}
const TypeKlassPtr *tkls = tp->isa_klassptr();
if (tkls != NULL && !StressReflectiveCode) {
if (tkls != NULL) {
if (tkls->is_loaded() && tkls->klass_is_exact()) {
ciKlass* klass = tkls->exact_klass();
// We are loading a field from a Klass metaobject whose identity
@ -2047,7 +2047,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const {
// (Folds up type checking code.)
assert(Opcode() == Op_LoadKlass, "must load a klass from _primary_supers");
ciKlass *ss = klass->super_of_depth(depth);
return ss ? TypeKlassPtr::make(ss) : TypePtr::NULL_PTR;
return ss ? TypeKlassPtr::make(ss, Type::trust_interfaces) : TypePtr::NULL_PTR;
}
const Type* aift = load_array_final_field(tkls, klass);
if (aift != NULL) return aift;
@ -2078,7 +2078,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const {
// (Folds up type checking code.)
assert(Opcode() == Op_LoadKlass, "must load a klass from _primary_supers");
ciKlass *ss = klass->super_of_depth(depth);
return ss ? TypeKlassPtr::make(ss) : TypePtr::NULL_PTR;
return ss ? TypeKlassPtr::make(ss, Type::trust_interfaces) : TypePtr::NULL_PTR;
}
}
}
@ -2338,14 +2338,14 @@ const Type* LoadNode::klass_value_common(PhaseGVN* phase) const {
// klass. Users of this result need to do a null check on the returned klass.
return TypePtr::NULL_PTR;
}
return TypeKlassPtr::make(ciArrayKlass::make(t));
return TypeKlassPtr::make(ciArrayKlass::make(t), Type::trust_interfaces);
}
if (!t->is_klass()) {
// a primitive Class (e.g., int.class) has NULL for a klass field
return TypePtr::NULL_PTR;
}
// (Folds up the 1st indirection in aClassConstant.getModifiers().)
return TypeKlassPtr::make(t->as_klass());
return TypeKlassPtr::make(t->as_klass(), Type::trust_interfaces);
}
// non-constant mirror, so we can't tell what's going on
}
@ -2383,7 +2383,7 @@ const Type* LoadNode::klass_value_common(PhaseGVN* phase) const {
ciKlass* sup = tkls->is_instklassptr()->instance_klass()->super();
// The field is Klass::_super. Return its (constant) value.
// (Folds up the 2nd indirection in aClassConstant.getSuperClass().)
return sup ? TypeKlassPtr::make(sup) : TypePtr::NULL_PTR;
return sup ? TypeKlassPtr::make(sup, Type::trust_interfaces) : TypePtr::NULL_PTR;
}
}

View File

@ -734,7 +734,6 @@ bool Node::is_dead() const {
for( uint i = 0; i < _max; i++ )
if( _in[i] != NULL )
return false;
dump();
return true;
}
@ -2543,10 +2542,7 @@ void Node::dump(const char* suffix, bool mark, outputStream* st, DumpConfig* dc)
if (t != NULL && (t->isa_instptr() || t->isa_instklassptr())) {
const TypeInstPtr *toop = t->isa_instptr();
const TypeInstKlassPtr *tkls = t->isa_instklassptr();
ciKlass* klass = toop ? toop->instance_klass() : (tkls ? tkls->instance_klass() : NULL );
if (klass && klass->is_loaded() && ((toop && toop->is_interface()) || (tkls && tkls->is_interface()))) {
st->print(" Interface:");
} else if (toop) {
if (toop) {
st->print(" Oop:");
} else if (tkls) {
st->print(" Klass:");

View File

@ -1197,7 +1197,7 @@ void Parse::do_method_entry() {
// Narrow receiver type when it is too broad for the method being parsed.
if (!method()->is_static()) {
ciInstanceKlass* callee_holder = method()->holder();
const Type* holder_type = TypeInstPtr::make(TypePtr::BotPTR, callee_holder);
const Type* holder_type = TypeInstPtr::make(TypePtr::BotPTR, callee_holder, Type::trust_interfaces);
Node* receiver_obj = local(0);
const TypeInstPtr* receiver_type = _gvn.type(receiver_obj)->isa_instptr();
@ -1210,7 +1210,7 @@ void Parse::do_method_entry() {
assert(callee_holder->is_interface(), "missing subtype check");
// Perform dynamic receiver subtype check against callee holder class w/ a halt on failure.
Node* holder_klass = _gvn.makecon(TypeKlassPtr::make(callee_holder));
Node* holder_klass = _gvn.makecon(TypeKlassPtr::make(callee_holder, Type::trust_interfaces));
Node* not_subtype_ctrl = gen_subtype_check(receiver_obj, holder_klass);
assert(!stopped(), "not a subtype");
@ -2130,7 +2130,7 @@ void Parse::clinit_deopt() {
set_parse_bci(0);
Node* holder = makecon(TypeKlassPtr::make(method()->holder()));
Node* holder = makecon(TypeKlassPtr::make(method()->holder(), Type::trust_interfaces));
guard_klass_being_initialized(holder);
}
@ -2209,27 +2209,6 @@ void Parse::return_current(Node* value) {
// cast from oop to interface allowed by the Verifier. Make it explicit
// here.
Node* phi = _exits.argument(0);
const TypeInstPtr *tr = phi->bottom_type()->isa_instptr();
if (tr && tr->is_loaded() &&
tr->is_interface()) {
const TypeInstPtr *tp = value->bottom_type()->isa_instptr();
if (tp && tp->is_loaded() &&
!tp->is_interface()) {
// sharpen the type eagerly; this eases certain assert checking
if (tp->higher_equal(TypeInstPtr::NOTNULL))
tr = tr->join_speculative(TypeInstPtr::NOTNULL)->is_instptr();
value = _gvn.transform(new CheckCastPPNode(0, value, tr));
}
} else {
// Also handle returns of oop-arrays to an arrays-of-interface return
const TypeInstPtr* phi_tip;
const TypeInstPtr* val_tip;
Type::get_arrays_base_elements(phi->bottom_type(), value->bottom_type(), &phi_tip, &val_tip);
if (phi_tip != NULL && phi_tip->is_loaded() && phi_tip->is_interface() &&
val_tip != NULL && val_tip->is_loaded() && !val_tip->is_interface()) {
value = _gvn.transform(new CheckCastPPNode(0, value, phi->bottom_type()));
}
}
phi->add_req(value);
}

View File

@ -277,7 +277,7 @@ void Parse::do_anewarray() {
kill_dead_locals();
const TypeKlassPtr* array_klass_type = TypeKlassPtr::make(array_klass);
const TypeKlassPtr* array_klass_type = TypeKlassPtr::make(array_klass, Type::trust_interfaces);
Node* count_val = pop();
Node* obj = new_array(makecon(array_klass_type), count_val, 1);
push(obj);
@ -299,7 +299,7 @@ void Parse::do_newarray(BasicType elem_type) {
Node* Parse::expand_multianewarray(ciArrayKlass* array_klass, Node* *lengths, int ndimensions, int nargs) {
Node* length = lengths[0];
assert(length != NULL, "");
Node* array = new_array(makecon(TypeKlassPtr::make(array_klass)), length, nargs);
Node* array = new_array(makecon(TypeKlassPtr::make(array_klass, Type::trust_interfaces)), length, nargs);
if (ndimensions > 1) {
jint length_con = find_int_con(length, -1);
guarantee(length_con >= 0, "non-constant multianewarray");
@ -385,7 +385,7 @@ void Parse::do_multianewarray() {
c = make_runtime_call(RC_NO_LEAF | RC_NO_IO,
OptoRuntime::multianewarray_Type(ndimensions),
fun, NULL, TypeRawPtr::BOTTOM,
makecon(TypeKlassPtr::make(array_klass)),
makecon(TypeKlassPtr::make(array_klass, Type::trust_interfaces)),
length[0], length[1], length[2],
(ndimensions > 2) ? length[3] : NULL,
(ndimensions > 3) ? length[4] : NULL);
@ -407,14 +407,14 @@ void Parse::do_multianewarray() {
c = make_runtime_call(RC_NO_LEAF | RC_NO_IO,
OptoRuntime::multianewarrayN_Type(),
OptoRuntime::multianewarrayN_Java(), NULL, TypeRawPtr::BOTTOM,
makecon(TypeKlassPtr::make(array_klass)),
makecon(TypeKlassPtr::make(array_klass, Type::trust_interfaces)),
dims);
}
make_slow_call_ex(c, env()->Throwable_klass(), false);
Node* res = _gvn.transform(new ProjNode(c, TypeFunc::Parms));
const Type* type = TypeOopPtr::make_from_klass_raw(array_klass);
const Type* type = TypeOopPtr::make_from_klass_raw(array_klass, Type::trust_interfaces);
// Improve the type: We know it's not null, exact, and of a given length.
type = type->is_ptr()->cast_to_ptr_type(TypePtr::NotNull);

View File

@ -90,7 +90,7 @@ void Parse::do_checkcast() {
return;
}
Node* res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass)));
Node* res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass, Type::trust_interfaces)));
if (stopped()) {
return;
}
@ -129,7 +129,7 @@ void Parse::do_instanceof() {
}
// Push the bool result back on stack
Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass)), true);
Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass, Type::trust_interfaces)), true);
// Pop from stack AFTER gen_instanceof because it can uncommon trap.
pop();

View File

@ -1080,7 +1080,7 @@ static inline Node* isa_const_java_mirror(PhaseGVN* phase, Node* n) {
// return the ConP(Foo.klass)
assert(mirror_type->is_klass(), "mirror_type should represent a Klass*");
return phase->makecon(TypeKlassPtr::make(mirror_type->as_klass()));
return phase->makecon(TypeKlassPtr::make(mirror_type->as_klass(), Type::trust_interfaces));
}
//------------------------------Ideal------------------------------------------

View File

@ -47,7 +47,7 @@ const Type* SubTypeCheckNode::sub(const Type* sub_t, const Type* super_t) const
}
if (subk != NULL) {
switch (Compile::current()->static_subtype_check(superk, subk)) {
switch (Compile::current()->static_subtype_check(superk, subk, false)) {
case Compile::SSC_always_false:
return TypeInt::CC_GT;
case Compile::SSC_always_true:

File diff suppressed because it is too large Load Diff

View File

@ -168,10 +168,6 @@ private:
// lazily, on demand, and cached in _dual.
const Type *_dual; // Cached dual value
#ifdef ASSERT
// One type is interface, the other is oop
virtual bool interface_vs_oop_helper(const Type *t) const;
#endif
const Type *meet_helper(const Type *t, bool include_speculative) const;
void check_symmetrical(const Type *t, const Type *mt) const;
@ -260,7 +256,6 @@ public:
// Modified version of JOIN adapted to the needs Node::Value.
// Normalizes all empty values to TOP. Does not kill _widen bits.
// Currently, it also works around limitations involving interface types.
// Variant that drops the speculative part of the types
const Type *filter(const Type *kills) const {
return filter_helper(kills, false);
@ -270,11 +265,6 @@ public:
return filter_helper(kills, true)->cleanup_speculative();
}
#ifdef ASSERT
// One type is interface, the other is oop
virtual bool interface_vs_oop(const Type *t) const;
#endif
// Returns true if this pointer points at memory which contains a
// compressed oop references.
bool is_ptr_to_narrowoop() const;
@ -404,8 +394,12 @@ public:
// Mapping to the array element's basic type.
BasicType array_element_basic_type() const;
enum InterfaceHandling {
trust_interfaces,
ignore_interfaces
};
// Create standard type for a ciType:
static const Type* get_const_type(ciType* type);
static const Type* get_const_type(ciType* type, InterfaceHandling interface_handling = ignore_interfaces);
// Create standard zero value:
static const Type* get_zero_type(BasicType type) {
@ -724,8 +718,8 @@ public:
}
static const TypeTuple *make( uint cnt, const Type **fields );
static const TypeTuple *make_range(ciSignature *sig);
static const TypeTuple *make_domain(ciInstanceKlass* recv, ciSignature *sig);
static const TypeTuple *make_range(ciSignature *sig, InterfaceHandling interface_handling = ignore_interfaces);
static const TypeTuple *make_domain(ciInstanceKlass* recv, ciSignature *sig, InterfaceHandling interface_handling);
// Subroutine call type with space allocated for argument types
// Memory for Control, I_O, Memory, FramePtr, and ReturnAdr is allocated implicitly
@ -776,10 +770,6 @@ public:
bool ary_must_be_exact() const; // true if arrays of such are never generic
virtual const TypeAry* remove_speculative() const;
virtual const Type* cleanup_speculative() const;
#ifdef ASSERT
// One type is interface, the other is oop
virtual bool interface_vs_oop(const Type *t) const;
#endif
#ifndef PRODUCT
virtual void dump2( Dict &d, uint, outputStream *st ) const; // Specialized per-Type dumping
#endif
@ -885,6 +875,52 @@ public:
// and the class will be inherited from.
class TypePtr : public Type {
friend class TypeNarrowPtr;
friend class Type;
protected:
class InterfaceSet {
private:
GrowableArray<ciKlass*> _list;
void raw_add(ciKlass* interface);
void add(ciKlass* interface);
void verify() const;
int _hash_computed:1;
int _exact_klass_computed:1;
int _is_loaded_computed:1;
int _hash;
ciKlass* _exact_klass;
bool _is_loaded;
void compute_hash();
void compute_exact_klass();
public:
InterfaceSet();
InterfaceSet(GrowableArray<ciInstanceKlass*>* interfaces);
bool eq(const InterfaceSet& other) const;
int hash() const;
void dump(outputStream *st) const;
InterfaceSet union_with(const InterfaceSet& other) const;
InterfaceSet intersection_with(const InterfaceSet& other) const;
bool contains(const InterfaceSet& other) const {
return intersection_with(other).eq(other);
}
bool empty() const { return _list.length() == 0; }
inline void* operator new(size_t x) throw() {
Compile* compile = Compile::current();
return compile->type_arena()->AmallocWords(x);
}
inline void operator delete( void* ptr ) {
ShouldNotReachHere();
}
ciKlass* exact_klass() const;
bool is_loaded() const;
static int compare(ciKlass* const &, ciKlass* const & k2);
void compute_is_loaded();
};
static InterfaceSet interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling);
public:
enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR };
protected:
@ -943,12 +979,20 @@ protected:
NOT_SUBTYPE,
LCA
};
static MeetResult
meet_instptr(PTR &ptr, ciKlass* this_klass, ciKlass* tinst_klass, bool this_xk, bool tinst_xk, PTR this_ptr,
PTR tinst_ptr, ciKlass*&res_klass, bool &res_xk);
static MeetResult
meet_aryptr(PTR& ptr, const Type*& elem, ciKlass* this_klass, ciKlass* tap_klass, bool this_xk, bool tap_xk, PTR this_ptr, PTR tap_ptr, ciKlass*& res_klass, bool& res_xk);
template<class T> static TypePtr::MeetResult meet_instptr(PTR& ptr, InterfaceSet& interfaces, const T* this_type,
const T* other_type, ciKlass*& res_klass, bool& res_xk);
template<class T> static MeetResult meet_aryptr(PTR& ptr, const Type*& elem, const T* this_ary, const T* other_ary,
ciKlass*& res_klass, bool& res_xk);
template <class T1, class T2> static bool is_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
template <class T1, class T2> static bool is_same_java_type_as_helper_for_instance(const T1* this_one, const T2* other);
template <class T1, class T2> static bool maybe_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
template <class T1, class T2> static bool is_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
template <class T1, class T2> static bool is_same_java_type_as_helper_for_array(const T1* this_one, const T2* other);
template <class T1, class T2> static bool maybe_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
template <class T1, class T2> static bool is_meet_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_xk, bool other_xk);
template <class T1, class T2> static bool is_meet_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_xk, bool other_xk);
public:
const int _offset; // Offset into oop, with TOP & BOT
const PTR _ptr; // Pointer equivalence class
@ -1057,7 +1101,7 @@ class TypeOopPtr : public TypePtr {
friend class TypeInstPtr;
friend class TypeAryPtr;
protected:
TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id,
TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset, int instance_id,
const TypePtr* speculative, int inline_depth);
public:
virtual bool eq( const Type *t ) const;
@ -1073,6 +1117,9 @@ protected:
ciObject* _const_oop; // Constant oop
// If _klass is NULL, then so is _sig. This is an unloaded klass.
ciKlass* _klass; // Klass object
const InterfaceSet _interfaces;
// Does the type exclude subclasses of the klass? (Inexact == polymorphic.)
bool _klass_is_exact;
bool _is_ptr_to_narrowoop;
@ -1084,11 +1131,13 @@ protected:
// This is the node index of the allocation node creating this instance.
int _instance_id;
static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact);
static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact, InterfaceHandling interface_handling);
int dual_instance_id() const;
int meet_instance_id(int uid) const;
InterfaceSet meet_interfaces(const TypeOopPtr* other) const;
// Do not allow interface-vs.-noninterface joins to collapse to top.
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
@ -1100,7 +1149,15 @@ public:
bool is_java_subtype_of(const TypeOopPtr* other) const {
return is_java_subtype_of_helper(other, klass_is_exact(), other->klass_is_exact());
}
virtual bool is_same_java_type_as(const TypeOopPtr* other) const { ShouldNotReachHere(); return false; }
bool is_same_java_type_as(const TypePtr* other) const {
return is_same_java_type_as_helper(other->is_oopptr());
}
virtual bool is_same_java_type_as_helper(const TypeOopPtr* other) const {
ShouldNotReachHere(); return false;
}
bool maybe_java_subtype_of(const TypeOopPtr* other) const {
return maybe_java_subtype_of_helper(other, klass_is_exact(), other->klass_is_exact());
}
@ -1111,18 +1168,18 @@ public:
// Creates a type given a klass. Correctly handles multi-dimensional arrays
// Respects UseUniqueSubclasses.
// If the klass is final, the resulting type will be exact.
static const TypeOopPtr* make_from_klass(ciKlass* klass) {
return make_from_klass_common(klass, true, false);
static const TypeOopPtr* make_from_klass(ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces) {
return make_from_klass_common(klass, true, false, interface_handling);
}
// Same as before, but will produce an exact type, even if
// the klass is not final, as long as it has exactly one implementation.
static const TypeOopPtr* make_from_klass_unique(ciKlass* klass) {
return make_from_klass_common(klass, true, true);
static const TypeOopPtr* make_from_klass_unique(ciKlass* klass, InterfaceHandling interface_handling= ignore_interfaces) {
return make_from_klass_common(klass, true, true, interface_handling);
}
// Same as before, but does not respects UseUniqueSubclasses.
// Use this only for creating array element types.
static const TypeOopPtr* make_from_klass_raw(ciKlass* klass) {
return make_from_klass_common(klass, false, false);
static const TypeOopPtr* make_from_klass_raw(ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces) {
return make_from_klass_common(klass, false, false, interface_handling);
}
// Creates a singleton type given an object.
// If the object cannot be rendered as a constant,
@ -1141,8 +1198,8 @@ public:
ciKlass* exact_klass(bool maybe_null = false) const { assert(klass_is_exact(), ""); ciKlass* k = exact_klass_helper(); assert(k != NULL || maybe_null, ""); return k; }
ciKlass* unloaded_klass() const { assert(!is_loaded(), "only for unloaded types"); return klass(); }
virtual bool is_loaded() const { return klass()->is_loaded(); }
bool klass_is_exact() const { return _klass_is_exact; }
virtual bool is_loaded() const { return klass()->is_loaded() && _interfaces.is_loaded(); }
virtual bool klass_is_exact() const { return _klass_is_exact; }
// Returns true if this pointer points at memory which contains a
// compressed oop references.
@ -1184,13 +1241,37 @@ public:
#ifndef PRODUCT
virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
#endif
private:
virtual bool is_meet_subtype_of(const TypePtr* other) const {
return is_meet_subtype_of_helper(other->is_oopptr(), klass_is_exact(), other->is_oopptr()->klass_is_exact());
}
virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const {
ShouldNotReachHere(); return false;
}
virtual const InterfaceSet interfaces() const {
return _interfaces;
};
const TypeOopPtr* is_reference_type(const Type* other) const {
return other->isa_oopptr();
}
const TypeAryPtr* is_array_type(const TypeOopPtr* other) const {
return other->isa_aryptr();
}
const TypeInstPtr* is_instance_type(const TypeOopPtr* other) const {
return other->isa_instptr();
}
};
//------------------------------TypeInstPtr------------------------------------
// Class of Java object pointers, pointing either to non-array Java instances
// or to a Klass* (including array klasses).
class TypeInstPtr : public TypeOopPtr {
TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id,
TypeInstPtr(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset, int instance_id,
const TypePtr* speculative, int inline_depth);
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
@ -1201,46 +1282,55 @@ public:
// Instance klass, ignoring any interface
ciInstanceKlass* instance_klass() const {
if (klass()->is_loaded() && klass()->is_interface()) {
return Compile::current()->env()->Object_klass();
}
assert(!(klass()->is_loaded() && klass()->is_interface()), "");
return klass()->as_instance_klass();
}
bool is_same_java_type_as(const TypeOopPtr* other) const;
bool is_same_java_type_as_helper(const TypeOopPtr* other) const;
bool is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const;
bool maybe_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const;
// Make a pointer to a constant oop.
static const TypeInstPtr *make(ciObject* o) {
return make(TypePtr::Constant, o->klass(), true, o, 0, InstanceBot);
ciKlass* k = o->klass();
const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
return make(TypePtr::Constant, k, interfaces, true, o, 0, InstanceBot);
}
// Make a pointer to a constant oop with offset.
static const TypeInstPtr *make(ciObject* o, int offset) {
return make(TypePtr::Constant, o->klass(), true, o, offset, InstanceBot);
ciKlass* k = o->klass();
const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
return make(TypePtr::Constant, k, interfaces, true, o, offset, InstanceBot);
}
// Make a pointer to some value of type klass.
static const TypeInstPtr *make(PTR ptr, ciKlass* klass) {
return make(ptr, klass, false, NULL, 0, InstanceBot);
static const TypeInstPtr *make(PTR ptr, ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces) {
const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling);
return make(ptr, klass, interfaces, false, NULL, 0, InstanceBot);
}
// Make a pointer to some non-polymorphic value of exactly type klass.
static const TypeInstPtr *make_exact(PTR ptr, ciKlass* klass) {
return make(ptr, klass, true, NULL, 0, InstanceBot);
const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces);
return make(ptr, klass, interfaces, true, NULL, 0, InstanceBot);
}
// Make a pointer to some value of type klass with offset.
static const TypeInstPtr *make(PTR ptr, ciKlass* klass, int offset) {
return make(ptr, klass, false, NULL, offset, InstanceBot);
const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces);
return make(ptr, klass, interfaces, false, NULL, offset, InstanceBot);
}
// Make a pointer to an oop.
static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset,
static const TypeInstPtr *make(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, bool xk, ciObject* o, int offset,
int instance_id = InstanceBot,
const TypePtr* speculative = NULL,
int inline_depth = InlineDepthBottom);
static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot) {
const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
return make(ptr, k, interfaces, xk, o, offset, instance_id);
}
/** Create constant type for a constant boxed value */
const Type* get_const_boxed_value() const;
@ -1265,13 +1355,11 @@ public:
// the core of the computation of the meet of 2 types
virtual const Type *xmeet_helper(const Type *t) const;
virtual const TypeInstPtr *xmeet_unloaded( const TypeInstPtr *t ) const;
virtual const TypeInstPtr *xmeet_unloaded(const TypeInstPtr *t, const InterfaceSet& interfaces) const;
virtual const Type *xdual() const; // Compute dual right now.
const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const;
bool is_interface() const { return is_loaded() && klass()->is_interface(); }
// Convenience common pre-built types.
static const TypeInstPtr *NOTNULL;
static const TypeInstPtr *BOTTOM;
@ -1281,34 +1369,38 @@ public:
#ifndef PRODUCT
virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
#endif
private:
virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const;
virtual bool is_meet_same_type_as(const TypePtr* other) const {
return _klass->equals(other->is_instptr()->_klass) && _interfaces.eq(other->is_instptr()->_interfaces);
}
};
//------------------------------TypeAryPtr-------------------------------------
// Class of Java array pointers
class TypeAryPtr : public TypeOopPtr {
friend class Type;
friend class TypePtr;
TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk,
int offset, int instance_id, bool is_autobox_cache,
const TypePtr* speculative, int inline_depth)
: TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative, inline_depth),
: TypeOopPtr(AryPtr,ptr,k,*_array_interfaces,xk,o,offset, instance_id, speculative, inline_depth),
_ary(ary),
_is_autobox_cache(is_autobox_cache)
{
#ifdef ASSERT
if (k != NULL) {
// Verify that specified klass and TypeAryPtr::klass() follow the same rules.
ciKlass* ck = compute_klass(true);
if (k != ck) {
this->dump(); tty->cr();
tty->print(" k: ");
k->print(); tty->cr();
tty->print("ck: ");
if (ck != NULL) ck->print();
else tty->print("<NULL>");
tty->cr();
assert(false, "unexpected TypeAryPtr::_klass");
}
int dummy;
bool top_or_bottom = (base_element_type(dummy) == Type::TOP || base_element_type(dummy) == Type::BOTTOM);
if (UseCompressedOops && (elem()->make_oopptr() != NULL && !top_or_bottom) &&
_offset != 0 && _offset != arrayOopDesc::length_offset_in_bytes() &&
_offset != arrayOopDesc::klass_offset_in_bytes()) {
_is_ptr_to_narrowoop = true;
}
#endif
}
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
@ -1317,12 +1409,16 @@ class TypeAryPtr : public TypeOopPtr {
ciKlass* compute_klass(DEBUG_ONLY(bool verify = false)) const;
// A pointer to delay allocation to Type::Initialize_shared()
static const InterfaceSet* _array_interfaces;
ciKlass* exact_klass_helper() const;
// Only guaranteed non null for array of basic types
ciKlass* klass() const;
public:
bool is_same_java_type_as(const TypeOopPtr* other) const;
bool is_same_java_type_as_helper(const TypeOopPtr* other) const;
bool is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const;
bool maybe_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const;
@ -1399,13 +1495,11 @@ public:
}
static const TypeAryPtr *_array_body_type[T_CONFLICT+1];
// sharpen the type of an int which is used as an array size
#ifdef ASSERT
// One type is interface, the other is oop
virtual bool interface_vs_oop(const Type *t) const;
#endif
#ifndef PRODUCT
virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
#endif
private:
virtual bool is_meet_subtype_of_helper(const TypeOopPtr* other, bool this_xk, bool other_xk) const;
};
//------------------------------TypeMetadataPtr-------------------------------------
@ -1453,8 +1547,9 @@ public:
class TypeKlassPtr : public TypePtr {
friend class TypeInstKlassPtr;
friend class TypeAryKlassPtr;
friend class TypePtr;
protected:
TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, int offset);
TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const InterfaceSet& interfaces, int offset);
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
@ -1466,7 +1561,8 @@ public:
protected:
ciKlass* _klass;
const InterfaceSet _interfaces;
InterfaceSet meet_interfaces(const TypeKlassPtr* other) const;
virtual bool must_be_exact() const { ShouldNotReachHere(); return false; }
virtual ciKlass* exact_klass_helper() const;
virtual ciKlass* klass() const { return _klass; }
@ -1476,20 +1572,23 @@ public:
bool is_java_subtype_of(const TypeKlassPtr* other) const {
return is_java_subtype_of_helper(other, klass_is_exact(), other->klass_is_exact());
}
bool is_same_java_type_as(const TypePtr* other) const {
return is_same_java_type_as_helper(other->is_klassptr());
}
bool maybe_java_subtype_of(const TypeKlassPtr* other) const {
return maybe_java_subtype_of_helper(other, klass_is_exact(), other->klass_is_exact());
}
virtual bool is_same_java_type_as(const TypeKlassPtr* other) const { ShouldNotReachHere(); return false; }
virtual bool is_same_java_type_as_helper(const TypeKlassPtr* other) const { ShouldNotReachHere(); return false; }
virtual bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const { ShouldNotReachHere(); return false; }
virtual bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const { ShouldNotReachHere(); return false; }
// Exact klass, possibly an interface or an array of interface
ciKlass* exact_klass(bool maybe_null = false) const { assert(klass_is_exact(), ""); ciKlass* k = exact_klass_helper(); assert(k != NULL || maybe_null, ""); return k; }
virtual bool klass_is_exact() const { return _ptr == Constant; }
bool klass_is_exact() const { return _ptr == Constant; }
static const TypeKlassPtr* make(ciKlass* klass);
static const TypeKlassPtr *make(PTR ptr, ciKlass* klass, int offset);
static const TypeKlassPtr* make(ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces);
static const TypeKlassPtr *make(PTR ptr, ciKlass* klass, int offset, InterfaceHandling interface_handling = ignore_interfaces);
virtual bool is_loaded() const { return _klass->is_loaded(); }
@ -1508,16 +1607,43 @@ public:
virtual const TypeKlassPtr* with_offset(intptr_t offset) const { ShouldNotReachHere(); return NULL; }
virtual const TypeKlassPtr* try_improve() const { return this; }
#ifndef PRODUCT
virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
#endif
private:
virtual bool is_meet_subtype_of(const TypePtr* other) const {
return is_meet_subtype_of_helper(other->is_klassptr(), klass_is_exact(), other->is_klassptr()->klass_is_exact());
}
virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const {
ShouldNotReachHere(); return false;
}
virtual const InterfaceSet interfaces() const {
return _interfaces;
};
const TypeKlassPtr* is_reference_type(const Type* other) const {
return other->isa_klassptr();
}
const TypeAryKlassPtr* is_array_type(const TypeKlassPtr* other) const {
return other->isa_aryklassptr();
}
const TypeInstKlassPtr* is_instance_type(const TypeKlassPtr* other) const {
return other->isa_instklassptr();
}
};
// Instance klass pointer, mirrors TypeInstPtr
class TypeInstKlassPtr : public TypeKlassPtr {
TypeInstKlassPtr(PTR ptr, ciKlass* klass, int offset)
: TypeKlassPtr(InstKlassPtr, ptr, klass, offset) {
TypeInstKlassPtr(PTR ptr, ciKlass* klass, const InterfaceSet& interfaces, int offset)
: TypeKlassPtr(InstKlassPtr, ptr, klass, interfaces, offset) {
assert(klass->is_instance_klass() && (!klass->is_loaded() || !klass->is_interface()), "");
}
virtual bool must_be_exact() const;
@ -1525,20 +1651,24 @@ class TypeInstKlassPtr : public TypeKlassPtr {
public:
// Instance klass ignoring any interface
ciInstanceKlass* instance_klass() const {
if (klass()->is_interface()) {
return Compile::current()->env()->Object_klass();
}
assert(!klass()->is_interface(), "");
return klass()->as_instance_klass();
}
bool is_same_java_type_as(const TypeKlassPtr* other) const;
bool is_same_java_type_as_helper(const TypeKlassPtr* other) const;
bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
static const TypeInstKlassPtr *make(ciKlass* k) {
return make(TypePtr::Constant, k, 0);
static const TypeInstKlassPtr *make(ciKlass* k, InterfaceHandling interface_handling) {
InterfaceSet interfaces = TypePtr::interfaces(k, true, true, false, interface_handling);
return make(TypePtr::Constant, k, interfaces, 0);
}
static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, const InterfaceSet& interfaces, int offset);
static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, int offset) {
const TypePtr::InterfaceSet interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
return make(ptr, k, interfaces, offset);
}
static const TypeInstKlassPtr *make(PTR ptr, ciKlass* k, int offset);
virtual const TypeInstKlassPtr* cast_to_ptr_type(PTR ptr) const;
@ -1554,23 +1684,31 @@ public:
virtual const Type *xdual() const;
virtual const TypeInstKlassPtr* with_offset(intptr_t offset) const;
bool is_interface() const { return klass()->is_interface(); }
virtual const TypeKlassPtr* try_improve() const;
// Convenience common pre-built types.
static const TypeInstKlassPtr* OBJECT; // Not-null object klass or below
static const TypeInstKlassPtr* OBJECT_OR_NULL; // Maybe-null version of same
private:
virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const;
};
// Array klass pointer, mirrors TypeAryPtr
class TypeAryKlassPtr : public TypeKlassPtr {
friend class TypeInstKlassPtr;
friend class Type;
friend class TypePtr;
const Type *_elem;
static const InterfaceSet* _array_interfaces;
TypeAryKlassPtr(PTR ptr, const Type *elem, ciKlass* klass, int offset)
: TypeKlassPtr(AryKlassPtr, ptr, klass, offset), _elem(elem) {
: TypeKlassPtr(AryKlassPtr, ptr, klass, *_array_interfaces, offset), _elem(elem) {
assert(klass == NULL || klass->is_type_array_klass() || !klass->as_obj_array_klass()->base_element_klass()->is_interface(), "");
}
virtual ciKlass* exact_klass_helper() const;
// Only guaranteed non null for array of basic types
virtual ciKlass* klass() const;
virtual bool must_be_exact() const;
@ -1580,16 +1718,16 @@ public:
// returns base element type, an instance klass (and not interface) for object arrays
const Type* base_element_type(int& dims) const;
static const TypeAryKlassPtr *make(PTR ptr, ciKlass* k, int offset);
static const TypeAryKlassPtr *make(PTR ptr, ciKlass* k, int offset, InterfaceHandling interface_handling);
bool is_same_java_type_as(const TypeKlassPtr* other) const;
bool is_same_java_type_as_helper(const TypeKlassPtr* other) const;
bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
bool is_loaded() const { return (_elem->isa_klassptr() ? _elem->is_klassptr()->is_loaded() : true); }
static const TypeAryKlassPtr *make(PTR ptr, const Type *elem, ciKlass* k, int offset);
static const TypeAryKlassPtr* make(ciKlass* klass);
static const TypeAryKlassPtr* make(ciKlass* klass, InterfaceHandling interface_handling);
const Type *elem() const { return _elem; }
@ -1616,6 +1754,8 @@ public:
#ifndef PRODUCT
virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
#endif
private:
virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const;
};
class TypeNarrowPtr : public Type {

View File

@ -132,7 +132,7 @@ public class CastNullCheckDroppingsTest {
t.runTest(methodClassCastNull, false, svalue);
t.runTest(methodNullClassCast, false, svalue);
t.runTest(methodClassCastObj, false, svalue);
t.runTest(methodObjClassCast, true, svalue);
t.runTest(methodObjClassCast, false, svalue);
t.runTest(methodClassCastInt, false, svalue);
t.runTest(methodIntClassCast, true, svalue);
t.runTest(methodClassCastint, false, svalue);

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022, Red Hat, Inc. 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 8297556
* @summary Parse::check_interpreter_type fails with assert "must constrain OSR typestate"
*
* @run main/othervm -Xbatch -XX:-TieredCompilation -XX:CompileOnly=TestExactArrayOfBasicType::test TestExactArrayOfBasicType
*
*/
public class TestExactArrayOfBasicType {
public static void test() {
int[][][][][] array = new int[1][2][3][4][5];
for (int i = 0; i < 50_000; ++i) {
array[0] = new int[0][1][2][3];
}
}
public static void main(String args[]) {
test();
}
}