8297933: [REDO] Compiler should only use verified interface types for optimization
Reviewed-by: kvn, vlivanov
This commit is contained in:
parent
9b1ade8e2b
commit
05a0a71031
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@ -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; }
|
||||
|
@ -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 &&
|
||||
|
@ -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.
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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:");
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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------------------------------------------
|
||||
|
@ -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
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user