8057622: java/util/stream/test/org/openjdk/tests/java/util/stream/InfiniteStreamWithLimitOpTest: SEGV inside compiled code (sparc)
In Parse::array_store_check(), add control edge FROM IfTrue branch of runtime type check of the destination array TO loading _element_klass from destination array. Reviewed-by: kvn, roland, anoll
This commit is contained in:
parent
8db9a55e68
commit
49b224a4f7
@ -794,7 +794,7 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) {
|
|||||||
Node* ex_klass_node = NULL;
|
Node* ex_klass_node = NULL;
|
||||||
if (has_ex_handler() && !ex_type->klass_is_exact()) {
|
if (has_ex_handler() && !ex_type->klass_is_exact()) {
|
||||||
Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes());
|
Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes());
|
||||||
ex_klass_node = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) );
|
ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
|
||||||
|
|
||||||
// Compute the exception klass a little more cleverly.
|
// Compute the exception klass a little more cleverly.
|
||||||
// Obvious solution is to simple do a LoadKlass from the 'ex_node'.
|
// Obvious solution is to simple do a LoadKlass from the 'ex_node'.
|
||||||
@ -812,7 +812,7 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes());
|
Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes());
|
||||||
Node* k = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) );
|
Node* k = _gvn.transform( LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
|
||||||
ex_klass_node->init_req( i, k );
|
ex_klass_node->init_req( i, k );
|
||||||
}
|
}
|
||||||
_gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT);
|
_gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT);
|
||||||
|
@ -1154,7 +1154,7 @@ Node* GraphKit::load_object_klass(Node* obj) {
|
|||||||
Node* akls = AllocateNode::Ideal_klass(obj, &_gvn);
|
Node* akls = AllocateNode::Ideal_klass(obj, &_gvn);
|
||||||
if (akls != NULL) return akls;
|
if (akls != NULL) return akls;
|
||||||
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
|
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
|
||||||
return _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS) );
|
return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS));
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------load_array_length-----------------------------------
|
//-------------------------load_array_length-----------------------------------
|
||||||
@ -2615,7 +2615,7 @@ Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, Me
|
|||||||
// types load from the super-class display table which is immutable.
|
// types load from the super-class display table which is immutable.
|
||||||
m = mem->memory_at(C->get_alias_index(gvn->type(p2)->is_ptr()));
|
m = mem->memory_at(C->get_alias_index(gvn->type(p2)->is_ptr()));
|
||||||
Node *kmem = might_be_cache ? m : C->immutable_memory();
|
Node *kmem = might_be_cache ? m : C->immutable_memory();
|
||||||
Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
|
Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, NULL, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
|
||||||
|
|
||||||
// Compile speed common case: ARE a subtype and we canNOT fail
|
// Compile speed common case: ARE a subtype and we canNOT fail
|
||||||
if( superklass == nkls )
|
if( superklass == nkls )
|
||||||
|
@ -3345,7 +3345,7 @@ Node* LibraryCallKit::load_klass_from_mirror_common(Node* mirror,
|
|||||||
if (region == NULL) never_see_null = true;
|
if (region == NULL) never_see_null = true;
|
||||||
Node* p = basic_plus_adr(mirror, offset);
|
Node* p = basic_plus_adr(mirror, offset);
|
||||||
const TypeKlassPtr* kls_type = TypeKlassPtr::OBJECT_OR_NULL;
|
const TypeKlassPtr* kls_type = TypeKlassPtr::OBJECT_OR_NULL;
|
||||||
Node* kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type));
|
Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type));
|
||||||
Node* null_ctl = top();
|
Node* null_ctl = top();
|
||||||
kls = null_check_oop(kls, &null_ctl, never_see_null);
|
kls = null_check_oop(kls, &null_ctl, never_see_null);
|
||||||
if (region != NULL) {
|
if (region != NULL) {
|
||||||
@ -3517,7 +3517,7 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
|
|||||||
phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror())));
|
phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror())));
|
||||||
// If we fall through, it's a plain class. Get its _super.
|
// If we fall through, it's a plain class. Get its _super.
|
||||||
p = basic_plus_adr(kls, in_bytes(Klass::super_offset()));
|
p = basic_plus_adr(kls, in_bytes(Klass::super_offset()));
|
||||||
kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
|
kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
|
||||||
null_ctl = top();
|
null_ctl = top();
|
||||||
kls = null_check_oop(kls, &null_ctl);
|
kls = null_check_oop(kls, &null_ctl);
|
||||||
if (null_ctl != top()) {
|
if (null_ctl != top()) {
|
||||||
@ -3671,7 +3671,7 @@ bool LibraryCallKit::inline_native_subtype_check() {
|
|||||||
args[which_arg] = arg;
|
args[which_arg] = arg;
|
||||||
|
|
||||||
Node* p = basic_plus_adr(arg, class_klass_offset);
|
Node* p = basic_plus_adr(arg, class_klass_offset);
|
||||||
Node* kls = LoadKlassNode::make(_gvn, immutable_memory(), p, adr_type, kls_type);
|
Node* kls = LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, adr_type, kls_type);
|
||||||
klasses[which_arg] = _gvn.transform(kls);
|
klasses[which_arg] = _gvn.transform(kls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2202,7 +2202,7 @@ void PhaseMacroExpand::expand_lock_node(LockNode *lock) {
|
|||||||
Node* klass_node = AllocateNode::Ideal_klass(obj, &_igvn);
|
Node* klass_node = AllocateNode::Ideal_klass(obj, &_igvn);
|
||||||
if (klass_node == NULL) {
|
if (klass_node == NULL) {
|
||||||
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
|
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
|
||||||
klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) );
|
klass_node = transform_later(LoadKlassNode::make(_igvn, NULL, mem, k_adr, _igvn.type(k_adr)->is_ptr()));
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
if (UseCompressedClassPointers && klass_node->is_DecodeNKlass()) {
|
if (UseCompressedClassPointers && klass_node->is_DecodeNKlass()) {
|
||||||
assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity");
|
assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity");
|
||||||
|
@ -529,7 +529,7 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode*
|
|||||||
// (At this point we can assume disjoint_bases, since types differ.)
|
// (At this point we can assume disjoint_bases, since types differ.)
|
||||||
int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
|
int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
|
||||||
Node* p1 = basic_plus_adr(dest_klass, ek_offset);
|
Node* p1 = basic_plus_adr(dest_klass, ek_offset);
|
||||||
Node* n1 = LoadKlassNode::make(_igvn, C->immutable_memory(), p1, TypeRawPtr::BOTTOM);
|
Node* n1 = LoadKlassNode::make(_igvn, NULL, C->immutable_memory(), p1, TypeRawPtr::BOTTOM);
|
||||||
Node* dest_elem_klass = transform_later(n1);
|
Node* dest_elem_klass = transform_later(n1);
|
||||||
Node* cv = generate_checkcast_arraycopy(&local_ctrl, &local_mem,
|
Node* cv = generate_checkcast_arraycopy(&local_ctrl, &local_mem,
|
||||||
adr_type,
|
adr_type,
|
||||||
|
@ -861,6 +861,10 @@ Node *MemNode::Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr ) {
|
|||||||
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
// Should LoadNode::Ideal() attempt to remove control edges?
|
||||||
|
bool LoadNode::can_remove_control() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
uint LoadNode::size_of() const { return sizeof(*this); }
|
uint LoadNode::size_of() const { return sizeof(*this); }
|
||||||
uint LoadNode::cmp( const Node &n ) const
|
uint LoadNode::cmp( const Node &n ) const
|
||||||
{ return !Type::cmp( _type, ((LoadNode&)n)._type ); }
|
{ return !Type::cmp( _type, ((LoadNode&)n)._type ); }
|
||||||
@ -1471,7 +1475,7 @@ Node *LoadNode::split_through_phi(PhaseGVN *phase) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------Ideal------------------------------------------
|
//------------------------------Ideal------------------------------------------
|
||||||
// If the load is from Field memory and the pointer is non-null, we can
|
// If the load is from Field memory and the pointer is non-null, it might be possible to
|
||||||
// zero out the control input.
|
// zero out the control input.
|
||||||
// If the offset is constant and the base is an object allocation,
|
// If the offset is constant and the base is an object allocation,
|
||||||
// try to hook me up to the exact initializing store.
|
// try to hook me up to the exact initializing store.
|
||||||
@ -1498,6 +1502,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
&& phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw) {
|
&& phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw) {
|
||||||
// Check for useless control edge in some common special cases
|
// Check for useless control edge in some common special cases
|
||||||
if (in(MemNode::Control) != NULL
|
if (in(MemNode::Control) != NULL
|
||||||
|
&& can_remove_control()
|
||||||
&& phase->type(base)->higher_equal(TypePtr::NOTNULL)
|
&& phase->type(base)->higher_equal(TypePtr::NOTNULL)
|
||||||
&& all_controls_dominate(base, phase->C->start())) {
|
&& all_controls_dominate(base, phase->C->start())) {
|
||||||
// A method-invariant, non-null address (constant or 'this' argument).
|
// A method-invariant, non-null address (constant or 'this' argument).
|
||||||
@ -2019,8 +2024,7 @@ const Type* LoadSNode::Value(PhaseTransform *phase) const {
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
//----------------------------LoadKlassNode::make------------------------------
|
//----------------------------LoadKlassNode::make------------------------------
|
||||||
// Polymorphic factory method:
|
// Polymorphic factory method:
|
||||||
Node *LoadKlassNode::make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk ) {
|
Node* LoadKlassNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk) {
|
||||||
Node *ctl = NULL;
|
|
||||||
// sanity check the alias category against the created node type
|
// sanity check the alias category against the created node type
|
||||||
const TypePtr *adr_type = adr->bottom_type()->isa_ptr();
|
const TypePtr *adr_type = adr->bottom_type()->isa_ptr();
|
||||||
assert(adr_type != NULL, "expecting TypeKlassPtr");
|
assert(adr_type != NULL, "expecting TypeKlassPtr");
|
||||||
@ -2040,6 +2044,12 @@ const Type *LoadKlassNode::Value( PhaseTransform *phase ) const {
|
|||||||
return klass_value_common(phase);
|
return klass_value_common(phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In most cases, LoadKlassNode does not have the control input set. If the control
|
||||||
|
// input is set, it must not be removed (by LoadNode::Ideal()).
|
||||||
|
bool LoadKlassNode::can_remove_control() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const Type *LoadNode::klass_value_common( PhaseTransform *phase ) const {
|
const Type *LoadNode::klass_value_common( PhaseTransform *phase ) const {
|
||||||
// Either input is TOP ==> the result is TOP
|
// Either input is TOP ==> the result is TOP
|
||||||
const Type *t1 = phase->type( in(MemNode::Memory) );
|
const Type *t1 = phase->type( in(MemNode::Memory) );
|
||||||
|
@ -148,6 +148,8 @@ private:
|
|||||||
protected:
|
protected:
|
||||||
virtual uint cmp(const Node &n) const;
|
virtual uint cmp(const Node &n) const;
|
||||||
virtual uint size_of() const; // Size is bigger
|
virtual uint size_of() const; // Size is bigger
|
||||||
|
// Should LoadNode::Ideal() attempt to remove control edges?
|
||||||
|
virtual bool can_remove_control() const;
|
||||||
const Type* const _type; // What kind of value is loaded?
|
const Type* const _type; // What kind of value is loaded?
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -171,8 +173,10 @@ public:
|
|||||||
// we are equivalent to. We look for Load of a Store.
|
// we are equivalent to. We look for Load of a Store.
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
|
||||||
// If the load is from Field memory and the pointer is non-null, we can
|
// If the load is from Field memory and the pointer is non-null, it might be possible to
|
||||||
// zero out the control input.
|
// zero out the control input.
|
||||||
|
// If the offset is constant and the base is an object allocation,
|
||||||
|
// try to hook me up to the exact initializing store.
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
|
||||||
// Split instance field load through Phi.
|
// Split instance field load through Phi.
|
||||||
@ -431,6 +435,10 @@ public:
|
|||||||
//------------------------------LoadKlassNode----------------------------------
|
//------------------------------LoadKlassNode----------------------------------
|
||||||
// Load a Klass from an object
|
// Load a Klass from an object
|
||||||
class LoadKlassNode : public LoadPNode {
|
class LoadKlassNode : public LoadPNode {
|
||||||
|
protected:
|
||||||
|
// In most cases, LoadKlassNode does not have the control input set. If the control
|
||||||
|
// input is set, it must not be removed (by LoadNode::Ideal()).
|
||||||
|
virtual bool can_remove_control() const;
|
||||||
public:
|
public:
|
||||||
LoadKlassNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk, MemOrd mo)
|
LoadKlassNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk, MemOrd mo)
|
||||||
: LoadPNode(c, mem, adr, at, tk, mo) {}
|
: LoadPNode(c, mem, adr, at, tk, mo) {}
|
||||||
@ -440,8 +448,8 @@ public:
|
|||||||
virtual bool depends_only_on_test() const { return true; }
|
virtual bool depends_only_on_test() const { return true; }
|
||||||
|
|
||||||
// Polymorphic factory method:
|
// Polymorphic factory method:
|
||||||
static Node* make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at,
|
static Node* make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at,
|
||||||
const TypeKlassPtr *tk = TypeKlassPtr::OBJECT );
|
const TypeKlassPtr* tk = TypeKlassPtr::OBJECT);
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------LoadNKlassNode---------------------------------
|
//------------------------------LoadNKlassNode---------------------------------
|
||||||
|
@ -1987,7 +1987,7 @@ void Parse::call_register_finalizer() {
|
|||||||
// finalization. In general this will fold up since the concrete
|
// finalization. In general this will fold up since the concrete
|
||||||
// class is often visible so the access flags are constant.
|
// class is often visible so the access flags are constant.
|
||||||
Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() );
|
Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() );
|
||||||
Node* klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS) );
|
Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), klass_addr, TypeInstPtr::KLASS));
|
||||||
|
|
||||||
Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::access_flags_offset()));
|
Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::access_flags_offset()));
|
||||||
Node* access_flags = make_load(NULL, access_flags_addr, TypeInt::INT, T_INT, MemNode::unordered);
|
Node* access_flags = make_load(NULL, access_flags_addr, TypeInt::INT, T_INT, MemNode::unordered);
|
||||||
|
@ -156,22 +156,43 @@ void Parse::array_store_check() {
|
|||||||
int klass_offset = oopDesc::klass_offset_in_bytes();
|
int klass_offset = oopDesc::klass_offset_in_bytes();
|
||||||
Node* p = basic_plus_adr( ary, ary, klass_offset );
|
Node* p = basic_plus_adr( ary, ary, klass_offset );
|
||||||
// p's type is array-of-OOPS plus klass_offset
|
// p's type is array-of-OOPS plus klass_offset
|
||||||
Node* array_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS) );
|
Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS));
|
||||||
// Get the array klass
|
// Get the array klass
|
||||||
const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr();
|
const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr();
|
||||||
|
|
||||||
// array_klass's type is generally INexact array-of-oop. Heroically
|
// The type of array_klass is usually INexact array-of-oop. Heroically
|
||||||
// cast the array klass to EXACT array and uncommon-trap if the cast
|
// cast array_klass to EXACT array and uncommon-trap if the cast fails.
|
||||||
// fails.
|
// Make constant out of the inexact array klass, but use it only if the cast
|
||||||
|
// succeeds.
|
||||||
bool always_see_exact_class = false;
|
bool always_see_exact_class = false;
|
||||||
if (MonomorphicArrayCheck
|
if (MonomorphicArrayCheck
|
||||||
&& !too_many_traps(Deoptimization::Reason_array_check)) {
|
&& !too_many_traps(Deoptimization::Reason_array_check)
|
||||||
|
&& !tak->klass_is_exact()
|
||||||
|
&& tak != TypeKlassPtr::OBJECT) {
|
||||||
|
// Regarding the fourth condition in the if-statement from above:
|
||||||
|
//
|
||||||
|
// If the compiler has determined that the type of array 'ary' (represented
|
||||||
|
// by 'array_klass') is java/lang/Object, the compiler must not assume that
|
||||||
|
// the array 'ary' is monomorphic.
|
||||||
|
//
|
||||||
|
// If 'ary' were of type java/lang/Object, this arraystore would have to fail,
|
||||||
|
// because it is not possible to perform a arraystore into an object that is not
|
||||||
|
// a "proper" array.
|
||||||
|
//
|
||||||
|
// Therefore, let's obtain at runtime the type of 'ary' and check if we can still
|
||||||
|
// successfully perform the store.
|
||||||
|
//
|
||||||
|
// The implementation reasons for the condition are the following:
|
||||||
|
//
|
||||||
|
// java/lang/Object is the superclass of all arrays, but it is represented by the VM
|
||||||
|
// as an InstanceKlass. The checks generated by gen_checkcast() (see below) expect
|
||||||
|
// 'array_klass' to be ObjArrayKlass, which can result in invalid memory accesses.
|
||||||
|
//
|
||||||
|
// See issue JDK-8057622 for details.
|
||||||
|
|
||||||
always_see_exact_class = true;
|
always_see_exact_class = true;
|
||||||
// (If no MDO at all, hope for the best, until a trap actually occurs.)
|
// (If no MDO at all, hope for the best, until a trap actually occurs.)
|
||||||
}
|
|
||||||
|
|
||||||
// Is the array klass is exactly its defined type?
|
|
||||||
if (always_see_exact_class && !tak->klass_is_exact()) {
|
|
||||||
// Make a constant out of the inexact array klass
|
// Make a constant out of the inexact array klass
|
||||||
const TypeKlassPtr *extak = tak->cast_to_exactness(true)->is_klassptr();
|
const TypeKlassPtr *extak = tak->cast_to_exactness(true)->is_klassptr();
|
||||||
Node* con = makecon(extak);
|
Node* con = makecon(extak);
|
||||||
@ -202,11 +223,15 @@ void Parse::array_store_check() {
|
|||||||
// Extract the array element class
|
// Extract the array element class
|
||||||
int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset());
|
int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset());
|
||||||
Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset);
|
Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset);
|
||||||
Node *a_e_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p2, tak) );
|
// We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true,
|
||||||
|
// we must set a control edge from the IfTrue node created by the uncommon_trap above to the
|
||||||
|
// LoadKlassNode.
|
||||||
|
Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : NULL,
|
||||||
|
immutable_memory(), p2, tak));
|
||||||
|
|
||||||
// Check (the hard way) and throw if not a subklass.
|
// Check (the hard way) and throw if not a subklass.
|
||||||
// Result is ignored, we just need the CFG effects.
|
// Result is ignored, we just need the CFG effects.
|
||||||
gen_checkcast( obj, a_e_klass );
|
gen_checkcast(obj, a_e_klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user