6723160: Nightly failure: Error: meet not symmetric
Add missing _instance_id settings and other EA fixes. Reviewed-by: rasbold
This commit is contained in:
parent
a8fc1db8c1
commit
fae39068e8
@ -3825,6 +3825,8 @@ int MatchRule::is_expensive() const {
|
|||||||
strcmp(opType,"ConvL2D")==0 ||
|
strcmp(opType,"ConvL2D")==0 ||
|
||||||
strcmp(opType,"ConvL2F")==0 ||
|
strcmp(opType,"ConvL2F")==0 ||
|
||||||
strcmp(opType,"ConvL2I")==0 ||
|
strcmp(opType,"ConvL2I")==0 ||
|
||||||
|
strcmp(opType,"DecodeN")==0 ||
|
||||||
|
strcmp(opType,"EncodeP")==0 ||
|
||||||
strcmp(opType,"RoundDouble")==0 ||
|
strcmp(opType,"RoundDouble")==0 ||
|
||||||
strcmp(opType,"RoundFloat")==0 ||
|
strcmp(opType,"RoundFloat")==0 ||
|
||||||
strcmp(opType,"ReverseBytesI")==0 ||
|
strcmp(opType,"ReverseBytesI")==0 ||
|
||||||
|
@ -631,61 +631,13 @@ uint CallNode::match_edge(uint idx) const {
|
|||||||
bool CallNode::may_modify(const TypePtr *addr_t, PhaseTransform *phase) {
|
bool CallNode::may_modify(const TypePtr *addr_t, PhaseTransform *phase) {
|
||||||
const TypeOopPtr *adrInst_t = addr_t->isa_oopptr();
|
const TypeOopPtr *adrInst_t = addr_t->isa_oopptr();
|
||||||
|
|
||||||
// if not an InstPtr or not an instance type, assume the worst
|
// If not an OopPtr or not an instance type, assume the worst.
|
||||||
if (adrInst_t == NULL || !adrInst_t->is_known_instance_field()) {
|
// Note: currently this method is called only for instance types.
|
||||||
|
if (adrInst_t == NULL || !adrInst_t->is_known_instance()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Compile *C = phase->C;
|
// The instance_id is set only for scalar-replaceable allocations which
|
||||||
int offset = adrInst_t->offset();
|
// are not passed as arguments according to Escape Analysis.
|
||||||
assert(adrInst_t->klass_is_exact() && offset >= 0, "should be valid offset");
|
|
||||||
ciKlass* adr_k = adrInst_t->klass();
|
|
||||||
assert(adr_k->is_loaded() &&
|
|
||||||
adr_k->is_java_klass() &&
|
|
||||||
!adr_k->is_interface(),
|
|
||||||
"only non-abstract classes are expected");
|
|
||||||
|
|
||||||
int base_idx = C->get_alias_index(adrInst_t);
|
|
||||||
int size = BytesPerLong; // If we don't know the size, assume largest.
|
|
||||||
if (adrInst_t->isa_instptr()) {
|
|
||||||
ciField* field = C->alias_type(base_idx)->field();
|
|
||||||
if (field != NULL) {
|
|
||||||
size = field->size_in_bytes();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert(adrInst_t->isa_aryptr(), "only arrays are expected");
|
|
||||||
size = type2aelembytes(adr_k->as_array_klass()->element_type()->basic_type());
|
|
||||||
}
|
|
||||||
|
|
||||||
ciMethod * meth = is_CallStaticJava() ? as_CallStaticJava()->method() : NULL;
|
|
||||||
BCEscapeAnalyzer *bcea = (meth != NULL) ? meth->get_bcea() : NULL;
|
|
||||||
|
|
||||||
const TypeTuple * d = tf()->domain();
|
|
||||||
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
|
|
||||||
const Type* t = d->field_at(i);
|
|
||||||
Node *arg = in(i);
|
|
||||||
const Type *at = phase->type(arg);
|
|
||||||
if (at == TypePtr::NULL_PTR || at == Type::TOP)
|
|
||||||
continue; // null can't affect anything
|
|
||||||
|
|
||||||
const TypeOopPtr *at_ptr = at->isa_oopptr();
|
|
||||||
if (!arg->is_top() && (t->isa_oopptr() != NULL ||
|
|
||||||
t->isa_ptr() && at_ptr != NULL)) {
|
|
||||||
assert(at_ptr != NULL, "expecting an OopPtr");
|
|
||||||
ciKlass* at_k = at_ptr->klass();
|
|
||||||
if ((adrInst_t->base() == at_ptr->base()) &&
|
|
||||||
at_k->is_loaded() &&
|
|
||||||
at_k->is_java_klass()) {
|
|
||||||
// If we have found an argument matching addr_t, check if the field
|
|
||||||
// at the specified offset is modified.
|
|
||||||
if ((at_k->is_interface() || adr_k == at_k ||
|
|
||||||
adr_k->is_subclass_of(at_k) && !at_ptr->klass_is_exact()) &&
|
|
||||||
(bcea == NULL ||
|
|
||||||
bcea->is_arg_modified(i - TypeFunc::Parms, offset, size))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,7 +713,9 @@ PhiNode* PhiNode::split_out_instance(const TypePtr* at, PhaseIterGVN *igvn) cons
|
|||||||
assert(type() == Type::MEMORY &&
|
assert(type() == Type::MEMORY &&
|
||||||
(t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
|
(t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
|
||||||
t->isa_oopptr() && !t->is_oopptr()->is_known_instance() &&
|
t->isa_oopptr() && !t->is_oopptr()->is_known_instance() &&
|
||||||
t->is_oopptr()->cast_to_instance_id(t_oop->instance_id()) == t_oop),
|
t->is_oopptr()->cast_to_exactness(true)
|
||||||
|
->is_oopptr()->cast_to_ptr_type(t_oop->ptr())
|
||||||
|
->is_oopptr()->cast_to_instance_id(t_oop->instance_id()) == t_oop),
|
||||||
"bottom or raw memory required");
|
"bottom or raw memory required");
|
||||||
|
|
||||||
// Check if an appropriate node already exists.
|
// Check if an appropriate node already exists.
|
||||||
@ -1089,6 +1091,8 @@ Node* PhiNode::unique_input(PhaseTransform* phase) {
|
|||||||
if (rc == NULL || phase->type(rc) == Type::TOP)
|
if (rc == NULL || phase->type(rc) == Type::TOP)
|
||||||
continue; // ignore unreachable control path
|
continue; // ignore unreachable control path
|
||||||
Node* n = in(i);
|
Node* n = in(i);
|
||||||
|
if (n == NULL)
|
||||||
|
continue;
|
||||||
Node* un = n->uncast();
|
Node* un = n->uncast();
|
||||||
if (un == NULL || un == this || phase->type(un) == Type::TOP) {
|
if (un == NULL || un == this || phase->type(un) == Type::TOP) {
|
||||||
continue; // ignore if top, or in(i) and "this" are in a data cycle
|
continue; // ignore if top, or in(i) and "this" are in a data cycle
|
||||||
|
@ -999,9 +999,14 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
|
|||||||
int offset = tj->offset();
|
int offset = tj->offset();
|
||||||
TypePtr::PTR ptr = tj->ptr();
|
TypePtr::PTR ptr = tj->ptr();
|
||||||
|
|
||||||
|
// Known instance (scalarizable allocation) alias only with itself.
|
||||||
|
bool is_known_inst = tj->isa_oopptr() != NULL &&
|
||||||
|
tj->is_oopptr()->is_known_instance();
|
||||||
|
|
||||||
// Process weird unsafe references.
|
// Process weird unsafe references.
|
||||||
if (offset == Type::OffsetBot && (tj->isa_instptr() /*|| tj->isa_klassptr()*/)) {
|
if (offset == Type::OffsetBot && (tj->isa_instptr() /*|| tj->isa_klassptr()*/)) {
|
||||||
assert(InlineUnsafeOps, "indeterminate pointers come only from unsafe ops");
|
assert(InlineUnsafeOps, "indeterminate pointers come only from unsafe ops");
|
||||||
|
assert(!is_known_inst, "scalarizable allocation should not have unsafe references");
|
||||||
tj = TypeOopPtr::BOTTOM;
|
tj = TypeOopPtr::BOTTOM;
|
||||||
ptr = tj->ptr();
|
ptr = tj->ptr();
|
||||||
offset = tj->offset();
|
offset = tj->offset();
|
||||||
@ -1009,14 +1014,20 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
|
|||||||
|
|
||||||
// Array pointers need some flattening
|
// Array pointers need some flattening
|
||||||
const TypeAryPtr *ta = tj->isa_aryptr();
|
const TypeAryPtr *ta = tj->isa_aryptr();
|
||||||
if( ta && _AliasLevel >= 2 ) {
|
if( ta && is_known_inst ) {
|
||||||
|
if ( offset != Type::OffsetBot &&
|
||||||
|
offset > arrayOopDesc::length_offset_in_bytes() ) {
|
||||||
|
offset = Type::OffsetBot; // Flatten constant access into array body only
|
||||||
|
tj = ta = TypeAryPtr::make(ptr, ta->ary(), ta->klass(), true, offset, ta->instance_id());
|
||||||
|
}
|
||||||
|
} else if( ta && _AliasLevel >= 2 ) {
|
||||||
// For arrays indexed by constant indices, we flatten the alias
|
// For arrays indexed by constant indices, we flatten the alias
|
||||||
// space to include all of the array body. Only the header, klass
|
// space to include all of the array body. Only the header, klass
|
||||||
// and array length can be accessed un-aliased.
|
// and array length can be accessed un-aliased.
|
||||||
if( offset != Type::OffsetBot ) {
|
if( offset != Type::OffsetBot ) {
|
||||||
if( ta->const_oop() ) { // methodDataOop or methodOop
|
if( ta->const_oop() ) { // methodDataOop or methodOop
|
||||||
offset = Type::OffsetBot; // Flatten constant access into array body
|
offset = Type::OffsetBot; // Flatten constant access into array body
|
||||||
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),ta->ary(),ta->klass(),false,Type::OffsetBot, ta->instance_id());
|
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),ta->ary(),ta->klass(),false,offset);
|
||||||
} else if( offset == arrayOopDesc::length_offset_in_bytes() ) {
|
} else if( offset == arrayOopDesc::length_offset_in_bytes() ) {
|
||||||
// range is OK as-is.
|
// range is OK as-is.
|
||||||
tj = ta = TypeAryPtr::RANGE;
|
tj = ta = TypeAryPtr::RANGE;
|
||||||
@ -1030,29 +1041,29 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
|
|||||||
ptr = TypePtr::BotPTR;
|
ptr = TypePtr::BotPTR;
|
||||||
} else { // Random constant offset into array body
|
} else { // Random constant offset into array body
|
||||||
offset = Type::OffsetBot; // Flatten constant access into array body
|
offset = Type::OffsetBot; // Flatten constant access into array body
|
||||||
tj = ta = TypeAryPtr::make(ptr,ta->ary(),ta->klass(),false,Type::OffsetBot, ta->instance_id());
|
tj = ta = TypeAryPtr::make(ptr,ta->ary(),ta->klass(),false,offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Arrays of fixed size alias with arrays of unknown size.
|
// Arrays of fixed size alias with arrays of unknown size.
|
||||||
if (ta->size() != TypeInt::POS) {
|
if (ta->size() != TypeInt::POS) {
|
||||||
const TypeAry *tary = TypeAry::make(ta->elem(), TypeInt::POS);
|
const TypeAry *tary = TypeAry::make(ta->elem(), TypeInt::POS);
|
||||||
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,ta->klass(),false,offset, ta->instance_id());
|
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,ta->klass(),false,offset);
|
||||||
}
|
}
|
||||||
// Arrays of known objects become arrays of unknown objects.
|
// Arrays of known objects become arrays of unknown objects.
|
||||||
if (ta->elem()->isa_narrowoop() && ta->elem() != TypeNarrowOop::BOTTOM) {
|
if (ta->elem()->isa_narrowoop() && ta->elem() != TypeNarrowOop::BOTTOM) {
|
||||||
const TypeAry *tary = TypeAry::make(TypeNarrowOop::BOTTOM, ta->size());
|
const TypeAry *tary = TypeAry::make(TypeNarrowOop::BOTTOM, ta->size());
|
||||||
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset, ta->instance_id());
|
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset);
|
||||||
}
|
}
|
||||||
if (ta->elem()->isa_oopptr() && ta->elem() != TypeInstPtr::BOTTOM) {
|
if (ta->elem()->isa_oopptr() && ta->elem() != TypeInstPtr::BOTTOM) {
|
||||||
const TypeAry *tary = TypeAry::make(TypeInstPtr::BOTTOM, ta->size());
|
const TypeAry *tary = TypeAry::make(TypeInstPtr::BOTTOM, ta->size());
|
||||||
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset, ta->instance_id());
|
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset);
|
||||||
}
|
}
|
||||||
// Arrays of bytes and of booleans both use 'bastore' and 'baload' so
|
// Arrays of bytes and of booleans both use 'bastore' and 'baload' so
|
||||||
// cannot be distinguished by bytecode alone.
|
// cannot be distinguished by bytecode alone.
|
||||||
if (ta->elem() == TypeInt::BOOL) {
|
if (ta->elem() == TypeInt::BOOL) {
|
||||||
const TypeAry *tary = TypeAry::make(TypeInt::BYTE, ta->size());
|
const TypeAry *tary = TypeAry::make(TypeInt::BYTE, ta->size());
|
||||||
ciKlass* aklass = ciTypeArrayKlass::make(T_BYTE);
|
ciKlass* aklass = ciTypeArrayKlass::make(T_BYTE);
|
||||||
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,aklass,false,offset, ta->instance_id());
|
tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,aklass,false,offset);
|
||||||
}
|
}
|
||||||
// During the 2nd round of IterGVN, NotNull castings are removed.
|
// During the 2nd round of IterGVN, NotNull castings are removed.
|
||||||
// Make sure the Bottom and NotNull variants alias the same.
|
// Make sure the Bottom and NotNull variants alias the same.
|
||||||
@ -1072,21 +1083,24 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
|
|||||||
if( ptr == TypePtr::Constant ) {
|
if( ptr == TypePtr::Constant ) {
|
||||||
// No constant oop pointers (such as Strings); they alias with
|
// No constant oop pointers (such as Strings); they alias with
|
||||||
// unknown strings.
|
// unknown strings.
|
||||||
|
assert(!is_known_inst, "not scalarizable allocation");
|
||||||
tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
|
tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
|
||||||
} else if( to->is_known_instance_field() ) {
|
} else if( is_known_inst ) {
|
||||||
tj = to; // Keep NotNull and klass_is_exact for instance type
|
tj = to; // Keep NotNull and klass_is_exact for instance type
|
||||||
} else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) {
|
} else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) {
|
||||||
// During the 2nd round of IterGVN, NotNull castings are removed.
|
// During the 2nd round of IterGVN, NotNull castings are removed.
|
||||||
// Make sure the Bottom and NotNull variants alias the same.
|
// Make sure the Bottom and NotNull variants alias the same.
|
||||||
// Also, make sure exact and non-exact variants alias the same.
|
// Also, make sure exact and non-exact variants alias the same.
|
||||||
tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset, to->instance_id());
|
tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
|
||||||
}
|
}
|
||||||
// Canonicalize the holder of this field
|
// Canonicalize the holder of this field
|
||||||
ciInstanceKlass *k = to->klass()->as_instance_klass();
|
ciInstanceKlass *k = to->klass()->as_instance_klass();
|
||||||
if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) {
|
if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) {
|
||||||
// First handle header references such as a LoadKlassNode, even if the
|
// First handle header references such as a LoadKlassNode, even if the
|
||||||
// object's klass is unloaded at compile time (4965979).
|
// object's klass is unloaded at compile time (4965979).
|
||||||
tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, offset, to->instance_id());
|
if (!is_known_inst) { // Do it only for non-instance types
|
||||||
|
tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, offset);
|
||||||
|
}
|
||||||
} else if (offset < 0 || offset >= k->size_helper() * wordSize) {
|
} else if (offset < 0 || offset >= k->size_helper() * wordSize) {
|
||||||
to = NULL;
|
to = NULL;
|
||||||
tj = TypeOopPtr::BOTTOM;
|
tj = TypeOopPtr::BOTTOM;
|
||||||
@ -1094,7 +1108,11 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
|
|||||||
} else {
|
} else {
|
||||||
ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset);
|
ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset);
|
||||||
if (!k->equals(canonical_holder) || tj->offset() != offset) {
|
if (!k->equals(canonical_holder) || tj->offset() != offset) {
|
||||||
tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, offset, to->instance_id());
|
if( is_known_inst ) {
|
||||||
|
tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, true, NULL, offset, to->instance_id());
|
||||||
|
} else {
|
||||||
|
tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1280,7 +1298,9 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr
|
|||||||
assert(flat != TypePtr::BOTTOM, "cannot alias-analyze an untyped ptr");
|
assert(flat != TypePtr::BOTTOM, "cannot alias-analyze an untyped ptr");
|
||||||
if (flat->isa_oopptr() && !flat->isa_klassptr()) {
|
if (flat->isa_oopptr() && !flat->isa_klassptr()) {
|
||||||
const TypeOopPtr* foop = flat->is_oopptr();
|
const TypeOopPtr* foop = flat->is_oopptr();
|
||||||
const TypePtr* xoop = foop->cast_to_exactness(!foop->klass_is_exact())->is_ptr();
|
// Scalarizable allocations have exact klass always.
|
||||||
|
bool exact = !foop->klass_is_exact() || foop->is_known_instance();
|
||||||
|
const TypePtr* xoop = foop->cast_to_exactness(exact)->is_ptr();
|
||||||
assert(foop == flatten_alias_type(xoop), "exactness must not affect alias type");
|
assert(foop == flatten_alias_type(xoop), "exactness must not affect alias type");
|
||||||
}
|
}
|
||||||
assert(flat == flatten_alias_type(flat), "exact bit doesn't matter");
|
assert(flat == flatten_alias_type(flat), "exact bit doesn't matter");
|
||||||
|
@ -717,12 +717,17 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_instance && result->is_Phi()) {
|
if (result->is_Phi()) {
|
||||||
PhiNode *mphi = result->as_Phi();
|
PhiNode *mphi = result->as_Phi();
|
||||||
assert(mphi->bottom_type() == Type::MEMORY, "memory phi required");
|
assert(mphi->bottom_type() == Type::MEMORY, "memory phi required");
|
||||||
const TypePtr *t = mphi->adr_type();
|
const TypePtr *t = mphi->adr_type();
|
||||||
if (C->get_alias_index(t) != alias_idx) {
|
if (C->get_alias_index(t) != alias_idx) {
|
||||||
|
// Create a new Phi with the specified alias index type.
|
||||||
result = split_memory_phi(mphi, alias_idx, orig_phis, phase);
|
result = split_memory_phi(mphi, alias_idx, orig_phis, phase);
|
||||||
|
} else if (!is_instance) {
|
||||||
|
// Push all non-instance Phis on the orig_phis worklist to update inputs
|
||||||
|
// during Phase 4 if needed.
|
||||||
|
orig_phis.append_if_missing(mphi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// the result is either MemNode, PhiNode, InitializeNode.
|
// the result is either MemNode, PhiNode, InitializeNode.
|
||||||
@ -859,10 +864,14 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
!n->is_CheckCastPP()) // not unique CheckCastPP.
|
!n->is_CheckCastPP()) // not unique CheckCastPP.
|
||||||
continue;
|
continue;
|
||||||
// The inline code for Object.clone() casts the allocation result to
|
// The inline code for Object.clone() casts the allocation result to
|
||||||
// java.lang.Object and then to the the actual type of the allocated
|
// java.lang.Object and then to the actual type of the allocated
|
||||||
// object. Detect this case and use the second cast.
|
// object. Detect this case and use the second cast.
|
||||||
|
// Also detect j.l.reflect.Array.newInstance(jobject, jint) case when
|
||||||
|
// the allocation result is cast to java.lang.Object and then
|
||||||
|
// to the actual Array type.
|
||||||
if (alloc->is_Allocate() && n->as_Type()->type() == TypeInstPtr::NOTNULL
|
if (alloc->is_Allocate() && n->as_Type()->type() == TypeInstPtr::NOTNULL
|
||||||
&& igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeKlassPtr::OBJECT) {
|
&& (alloc->is_AllocateArray() ||
|
||||||
|
igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeKlassPtr::OBJECT)) {
|
||||||
Node *cast2 = NULL;
|
Node *cast2 = NULL;
|
||||||
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
|
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
|
||||||
Node *use = n->fast_out(i);
|
Node *use = n->fast_out(i);
|
||||||
@ -878,7 +887,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
set_escape_state(n->_idx, es);
|
set_escape_state(n->_idx, es);
|
||||||
// in order for an object to be stackallocatable, it must be:
|
// in order for an object to be scalar-replaceable, it must be:
|
||||||
// - a direct allocation (not a call returning an object)
|
// - a direct allocation (not a call returning an object)
|
||||||
// - non-escaping
|
// - non-escaping
|
||||||
// - eligible to be a unique type
|
// - eligible to be a unique type
|
||||||
@ -888,7 +897,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
|
const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
continue; // not a TypeInstPtr
|
continue; // not a TypeInstPtr
|
||||||
tinst = t->cast_to_instance_id(ni);
|
tinst = t->cast_to_exactness(true)->is_oopptr()->cast_to_instance_id(ni);
|
||||||
igvn->hash_delete(n);
|
igvn->hash_delete(n);
|
||||||
igvn->set_type(n, tinst);
|
igvn->set_type(n, tinst);
|
||||||
n->raise_bottom_type(tinst);
|
n->raise_bottom_type(tinst);
|
||||||
@ -1204,8 +1213,8 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
// to recursively process Phi's encounted on the input memory
|
// to recursively process Phi's encounted on the input memory
|
||||||
// chains as is done in split_memory_phi() since they will
|
// chains as is done in split_memory_phi() since they will
|
||||||
// also be processed here.
|
// also be processed here.
|
||||||
while (orig_phis.length() != 0) {
|
for (int j = 0; j < orig_phis.length(); j++) {
|
||||||
PhiNode *phi = orig_phis.pop();
|
PhiNode *phi = orig_phis.at(j);
|
||||||
int alias_idx = _compile->get_alias_index(phi->adr_type());
|
int alias_idx = _compile->get_alias_index(phi->adr_type());
|
||||||
igvn->hash_delete(phi);
|
igvn->hash_delete(phi);
|
||||||
for (uint i = 1; i < phi->req(); i++) {
|
for (uint i = 1; i < phi->req(); i++) {
|
||||||
|
@ -231,8 +231,7 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me
|
|||||||
} else {
|
} else {
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
if (mem == orig_mem)
|
assert(mem != orig_mem, "dead memory loop");
|
||||||
return mem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,21 +240,44 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me
|
|||||||
// on the input paths.
|
// on the input paths.
|
||||||
// Note: this function is recursive, its depth is limied by the "level" argument
|
// Note: this function is recursive, its depth is limied by the "level" argument
|
||||||
// Returns the computed Phi, or NULL if it cannot compute it.
|
// Returns the computed Phi, or NULL if it cannot compute it.
|
||||||
Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *phi_type, const TypeOopPtr *adr_t, Node *alloc, int level) {
|
Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *phi_type, const TypeOopPtr *adr_t, Node *alloc, Node_Stack *value_phis, int level) {
|
||||||
|
assert(mem->is_Phi(), "sanity");
|
||||||
if (level <= 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
int alias_idx = C->get_alias_index(adr_t);
|
int alias_idx = C->get_alias_index(adr_t);
|
||||||
int offset = adr_t->offset();
|
int offset = adr_t->offset();
|
||||||
int instance_id = adr_t->instance_id();
|
int instance_id = adr_t->instance_id();
|
||||||
|
|
||||||
|
// Check if an appropriate value phi already exists.
|
||||||
|
Node* region = mem->in(0);
|
||||||
|
for (DUIterator_Fast kmax, k = region->fast_outs(kmax); k < kmax; k++) {
|
||||||
|
Node* phi = region->fast_out(k);
|
||||||
|
if (phi->is_Phi() && phi != mem &&
|
||||||
|
phi->as_Phi()->is_same_inst_field(phi_type, instance_id, alias_idx, offset)) {
|
||||||
|
return phi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if an appropriate new value phi already exists.
|
||||||
|
Node* new_phi = NULL;
|
||||||
|
uint size = value_phis->size();
|
||||||
|
for (uint i=0; i < size; i++) {
|
||||||
|
if ( mem->_idx == value_phis->index_at(i) ) {
|
||||||
|
return value_phis->node_at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level <= 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
|
Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
|
||||||
Node *alloc_mem = alloc->in(TypeFunc::Memory);
|
Node *alloc_mem = alloc->in(TypeFunc::Memory);
|
||||||
|
|
||||||
uint length = mem->req();
|
uint length = mem->req();
|
||||||
GrowableArray <Node *> values(length, length, NULL);
|
GrowableArray <Node *> values(length, length, NULL);
|
||||||
|
|
||||||
|
// create a new Phi for the value
|
||||||
|
PhiNode *phi = new (C, length) PhiNode(mem->in(0), phi_type, NULL, instance_id, alias_idx, offset);
|
||||||
|
transform_later(phi);
|
||||||
|
value_phis->push(phi, mem->_idx);
|
||||||
|
|
||||||
for (uint j = 1; j < length; j++) {
|
for (uint j = 1; j < length; j++) {
|
||||||
Node *in = mem->in(j);
|
Node *in = mem->in(j);
|
||||||
if (in == NULL || in->is_top()) {
|
if (in == NULL || in->is_top()) {
|
||||||
@ -280,33 +302,17 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
|
|||||||
} else if(val->is_Proj() && val->in(0) == alloc) {
|
} else if(val->is_Proj() && val->in(0) == alloc) {
|
||||||
values.at_put(j, _igvn.zerocon(ft));
|
values.at_put(j, _igvn.zerocon(ft));
|
||||||
} else if (val->is_Phi()) {
|
} else if (val->is_Phi()) {
|
||||||
// Check if an appropriate node already exists.
|
val = value_from_mem_phi(val, ft, phi_type, adr_t, alloc, value_phis, level-1);
|
||||||
Node* region = val->in(0);
|
if (val == NULL) {
|
||||||
Node* old_phi = NULL;
|
return NULL;
|
||||||
for (DUIterator_Fast kmax, k = region->fast_outs(kmax); k < kmax; k++) {
|
|
||||||
Node* phi = region->fast_out(k);
|
|
||||||
if (phi->is_Phi() && phi != val &&
|
|
||||||
phi->as_Phi()->is_same_inst_field(phi_type, instance_id, alias_idx, offset)) {
|
|
||||||
old_phi = phi;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (old_phi == NULL) {
|
|
||||||
val = value_from_mem_phi(val, ft, phi_type, adr_t, alloc, level-1);
|
|
||||||
if (val == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
values.at_put(j, val);
|
|
||||||
} else {
|
|
||||||
values.at_put(j, old_phi);
|
|
||||||
}
|
}
|
||||||
|
values.at_put(j, val);
|
||||||
} else {
|
} else {
|
||||||
return NULL; // unknown node on this path
|
return NULL; // unknown node on this path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// create a new Phi for the value
|
// Set Phi's inputs
|
||||||
PhiNode *phi = new (C, length) PhiNode(mem->in(0), phi_type, NULL, instance_id, alias_idx, offset);
|
|
||||||
for (uint j = 1; j < length; j++) {
|
for (uint j = 1; j < length; j++) {
|
||||||
if (values.at(j) == mem) {
|
if (values.at(j) == mem) {
|
||||||
phi->init_req(j, phi);
|
phi->init_req(j, phi);
|
||||||
@ -314,7 +320,6 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
|
|||||||
phi->init_req(j, values.at(j));
|
phi->init_req(j, values.at(j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transform_later(phi);
|
|
||||||
return phi;
|
return phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,7 +334,8 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, BasicType ft, const Type
|
|||||||
Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
|
Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
|
||||||
Node *alloc_ctrl = alloc->in(TypeFunc::Control);
|
Node *alloc_ctrl = alloc->in(TypeFunc::Control);
|
||||||
Node *alloc_mem = alloc->in(TypeFunc::Memory);
|
Node *alloc_mem = alloc->in(TypeFunc::Memory);
|
||||||
VectorSet visited(Thread::current()->resource_area());
|
Arena *a = Thread::current()->resource_area();
|
||||||
|
VectorSet visited(a);
|
||||||
|
|
||||||
|
|
||||||
bool done = sfpt_mem == alloc_mem;
|
bool done = sfpt_mem == alloc_mem;
|
||||||
@ -389,9 +395,18 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, BasicType ft, const Type
|
|||||||
return mem->in(MemNode::ValueIn);
|
return mem->in(MemNode::ValueIn);
|
||||||
} else if (mem->is_Phi()) {
|
} else if (mem->is_Phi()) {
|
||||||
// attempt to produce a Phi reflecting the values on the input paths of the Phi
|
// attempt to produce a Phi reflecting the values on the input paths of the Phi
|
||||||
Node * phi = value_from_mem_phi(mem, ft, ftype, adr_t, alloc, 8);
|
Node_Stack value_phis(a, 8);
|
||||||
|
Node * phi = value_from_mem_phi(mem, ft, ftype, adr_t, alloc, &value_phis, 8);
|
||||||
if (phi != NULL) {
|
if (phi != NULL) {
|
||||||
return phi;
|
return phi;
|
||||||
|
} else {
|
||||||
|
// Kill all new Phis
|
||||||
|
while(value_phis.is_nonempty()) {
|
||||||
|
Node* n = value_phis.node();
|
||||||
|
_igvn.hash_delete(n);
|
||||||
|
_igvn.subsume_node(n, C->top());
|
||||||
|
value_phis.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ private:
|
|||||||
const TypeFunc* slow_call_type,
|
const TypeFunc* slow_call_type,
|
||||||
address slow_call_address);
|
address slow_call_address);
|
||||||
Node *value_from_mem(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc);
|
Node *value_from_mem(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc);
|
||||||
Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc, int level);
|
Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, Node *alloc, Node_Stack *value_phis, int level);
|
||||||
|
|
||||||
bool eliminate_allocate_node(AllocateNode *alloc);
|
bool eliminate_allocate_node(AllocateNode *alloc);
|
||||||
bool can_eliminate_allocation(AllocateNode *alloc, GrowableArray <SafePointNode *>& safepoints);
|
bool can_eliminate_allocation(AllocateNode *alloc, GrowableArray <SafePointNode *>& safepoints);
|
||||||
|
@ -135,7 +135,9 @@ Node *MemNode::optimize_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGV
|
|||||||
const TypePtr *t = mphi->adr_type();
|
const TypePtr *t = mphi->adr_type();
|
||||||
if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
|
if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
|
||||||
t->isa_oopptr() && !t->is_oopptr()->is_known_instance() &&
|
t->isa_oopptr() && !t->is_oopptr()->is_known_instance() &&
|
||||||
t->is_oopptr()->cast_to_instance_id(t_oop->instance_id()) == t_oop) {
|
t->is_oopptr()->cast_to_exactness(true)
|
||||||
|
->is_oopptr()->cast_to_ptr_type(t_oop->ptr())
|
||||||
|
->is_oopptr()->cast_to_instance_id(t_oop->instance_id()) == t_oop) {
|
||||||
// clone the Phi with our address type
|
// clone the Phi with our address type
|
||||||
result = mphi->split_out_instance(t_adr, igvn);
|
result = mphi->split_out_instance(t_adr, igvn);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1399,6 +1399,10 @@ public:
|
|||||||
uint index() const {
|
uint index() const {
|
||||||
return _inode_top->indx;
|
return _inode_top->indx;
|
||||||
}
|
}
|
||||||
|
uint index_at(uint i) const {
|
||||||
|
assert(_inodes + i <= _inode_top, "in range");
|
||||||
|
return _inodes[i].indx;
|
||||||
|
}
|
||||||
void set_node(Node *n) {
|
void set_node(Node *n) {
|
||||||
_inode_top->node = n;
|
_inode_top->node = n;
|
||||||
}
|
}
|
||||||
|
@ -2218,7 +2218,7 @@ const Type *TypeOopPtr::cast_to_ptr_type(PTR ptr) const {
|
|||||||
return make(ptr, _offset);
|
return make(ptr, _offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------cast_to_instance-------------------------------
|
//-----------------------------cast_to_instance_id----------------------------
|
||||||
const TypeOopPtr *TypeOopPtr::cast_to_instance_id(int instance_id) const {
|
const TypeOopPtr *TypeOopPtr::cast_to_instance_id(int instance_id) const {
|
||||||
// There are no instances of a general oop.
|
// There are no instances of a general oop.
|
||||||
// Return self unchanged.
|
// Return self unchanged.
|
||||||
@ -2610,8 +2610,7 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr,
|
|||||||
// Ptr is never Null
|
// Ptr is never Null
|
||||||
assert( ptr != Null, "NULL pointers are not typed" );
|
assert( ptr != Null, "NULL pointers are not typed" );
|
||||||
|
|
||||||
if ( instance_id > 0 )
|
assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
|
||||||
xk = true; // instances are always exactly typed
|
|
||||||
if (!UseExactTypes) xk = false;
|
if (!UseExactTypes) xk = false;
|
||||||
if (ptr == Constant) {
|
if (ptr == Constant) {
|
||||||
// Note: This case includes meta-object constants, such as methods.
|
// Note: This case includes meta-object constants, such as methods.
|
||||||
@ -2650,16 +2649,10 @@ const Type *TypeInstPtr::cast_to_exactness(bool klass_is_exact) const {
|
|||||||
return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id);
|
return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------cast_to_instance-------------------------------
|
//-----------------------------cast_to_instance_id----------------------------
|
||||||
const TypeOopPtr *TypeInstPtr::cast_to_instance_id(int instance_id) const {
|
const TypeOopPtr *TypeInstPtr::cast_to_instance_id(int instance_id) const {
|
||||||
if( instance_id == _instance_id ) return this;
|
if( instance_id == _instance_id ) return this;
|
||||||
bool exact = _klass_is_exact;
|
return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id);
|
||||||
PTR ptr_t = _ptr;
|
|
||||||
if ( instance_id > 0 ) { // instances are always exactly typed
|
|
||||||
if (UseExactTypes) exact = true;
|
|
||||||
ptr_t = NotNull;
|
|
||||||
}
|
|
||||||
return make(ptr_t, klass(), exact, const_oop(), _offset, instance_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------xmeet_unloaded---------------------------------
|
//------------------------------xmeet_unloaded---------------------------------
|
||||||
@ -2899,6 +2892,7 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
|||||||
xk = above_centerline(ptr) ? tinst_xk : false;
|
xk = above_centerline(ptr) ? tinst_xk : false;
|
||||||
// Watch out for Constant vs. AnyNull interface.
|
// Watch out for Constant vs. AnyNull interface.
|
||||||
if (ptr == Constant) ptr = NotNull; // forget it was a constant
|
if (ptr == Constant) ptr = NotNull; // forget it was a constant
|
||||||
|
instance_id = InstanceBot;
|
||||||
}
|
}
|
||||||
ciObject* o = NULL; // the Constant value, if any
|
ciObject* o = NULL; // the Constant value, if any
|
||||||
if (ptr == Constant) {
|
if (ptr == Constant) {
|
||||||
@ -2989,6 +2983,7 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
|||||||
// class hierarchy - which means we have to fall to at least NotNull.
|
// class hierarchy - which means we have to fall to at least NotNull.
|
||||||
if( ptr == TopPTR || ptr == AnyNull || ptr == Constant )
|
if( ptr == TopPTR || ptr == AnyNull || ptr == Constant )
|
||||||
ptr = NotNull;
|
ptr = NotNull;
|
||||||
|
instance_id = InstanceBot;
|
||||||
|
|
||||||
// Now we find the LCA of Java classes
|
// Now we find the LCA of Java classes
|
||||||
ciKlass* k = this_klass->least_common_ancestor(tinst_klass);
|
ciKlass* k = this_klass->least_common_ancestor(tinst_klass);
|
||||||
@ -3101,8 +3096,7 @@ const TypeAryPtr *TypeAryPtr::make( PTR ptr, const TypeAry *ary, ciKlass* k, boo
|
|||||||
assert(!(k == NULL && ary->_elem->isa_int()),
|
assert(!(k == NULL && ary->_elem->isa_int()),
|
||||||
"integral arrays must be pre-equipped with a class");
|
"integral arrays must be pre-equipped with a class");
|
||||||
if (!xk) xk = ary->ary_must_be_exact();
|
if (!xk) xk = ary->ary_must_be_exact();
|
||||||
if ( instance_id > 0 )
|
assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
|
||||||
xk = true; // instances are always exactly typed
|
|
||||||
if (!UseExactTypes) xk = (ptr == Constant);
|
if (!UseExactTypes) xk = (ptr == Constant);
|
||||||
return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id))->hashcons();
|
return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id))->hashcons();
|
||||||
}
|
}
|
||||||
@ -3113,8 +3107,7 @@ const TypeAryPtr *TypeAryPtr::make( PTR ptr, ciObject* o, const TypeAry *ary, ci
|
|||||||
"integral arrays must be pre-equipped with a class");
|
"integral arrays must be pre-equipped with a class");
|
||||||
assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
|
assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
|
||||||
if (!xk) xk = (o != NULL) || ary->ary_must_be_exact();
|
if (!xk) xk = (o != NULL) || ary->ary_must_be_exact();
|
||||||
if ( instance_id > 0 )
|
assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
|
||||||
xk = true; // instances are always exactly typed
|
|
||||||
if (!UseExactTypes) xk = (ptr == Constant);
|
if (!UseExactTypes) xk = (ptr == Constant);
|
||||||
return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id))->hashcons();
|
return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id))->hashcons();
|
||||||
}
|
}
|
||||||
@ -3134,16 +3127,10 @@ const Type *TypeAryPtr::cast_to_exactness(bool klass_is_exact) const {
|
|||||||
return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id);
|
return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------cast_to_instance-------------------------------
|
//-----------------------------cast_to_instance_id----------------------------
|
||||||
const TypeOopPtr *TypeAryPtr::cast_to_instance_id(int instance_id) const {
|
const TypeOopPtr *TypeAryPtr::cast_to_instance_id(int instance_id) const {
|
||||||
if( instance_id == _instance_id ) return this;
|
if( instance_id == _instance_id ) return this;
|
||||||
bool exact = _klass_is_exact;
|
return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id);
|
||||||
PTR ptr_t = _ptr;
|
|
||||||
if ( instance_id > 0 ) { // instances are always exactly typed
|
|
||||||
if (UseExactTypes) exact = true;
|
|
||||||
ptr_t = NotNull;
|
|
||||||
}
|
|
||||||
return make(ptr_t, const_oop(), _ary, klass(), exact, _offset, instance_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------narrow_size_type-------------------------------
|
//-----------------------------narrow_size_type-------------------------------
|
||||||
@ -3300,6 +3287,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
|||||||
} else {
|
} else {
|
||||||
// Something like byte[int+] meets char[int+].
|
// Something like byte[int+] meets char[int+].
|
||||||
// This must fall to bottom, not (int[-128..65535])[int+].
|
// This must fall to bottom, not (int[-128..65535])[int+].
|
||||||
|
instance_id = InstanceBot;
|
||||||
tary = TypeAry::make(Type::BOTTOM, tary->_size);
|
tary = TypeAry::make(Type::BOTTOM, tary->_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3316,6 +3304,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
|||||||
if( tap->const_oop() != NULL && !o->equals(tap->const_oop()) ) {
|
if( tap->const_oop() != NULL && !o->equals(tap->const_oop()) ) {
|
||||||
ptr = NotNull;
|
ptr = NotNull;
|
||||||
o = NULL;
|
o = NULL;
|
||||||
|
instance_id = InstanceBot;
|
||||||
}
|
}
|
||||||
} else if( above_centerline(_ptr) ) {
|
} else if( above_centerline(_ptr) ) {
|
||||||
o = tap->const_oop();
|
o = tap->const_oop();
|
||||||
|
98
hotspot/test/compiler/6724218/Test.java
Normal file
98
hotspot/test/compiler/6724218/Test.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008 Sun Microsystems, 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 6724218
|
||||||
|
* @summary Fix raise_LCA_above_marks() early termination
|
||||||
|
* @run main/othervm -Xbatch -XX:CompileCommand=exclude,Test.update Test
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Test {
|
||||||
|
Test next = null;
|
||||||
|
Object value = null;
|
||||||
|
|
||||||
|
static boolean _closed = false;
|
||||||
|
static int size = 0;
|
||||||
|
static Test list = null;
|
||||||
|
static int cache_size = 0;
|
||||||
|
static Test cache = null;
|
||||||
|
|
||||||
|
Object get(int i) {
|
||||||
|
Test t = list;
|
||||||
|
list = t.next;
|
||||||
|
size -= 1;
|
||||||
|
Object o = t.value;
|
||||||
|
if (i > 0) {
|
||||||
|
t.next = cache;
|
||||||
|
t.value = null;
|
||||||
|
cache = t;
|
||||||
|
cache_size = +1;
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() {
|
||||||
|
// Exclude compilation of this one.
|
||||||
|
if (size == 0) {
|
||||||
|
Test t;
|
||||||
|
if (cache_size > 0) {
|
||||||
|
t = cache;
|
||||||
|
cache = t.next;
|
||||||
|
cache_size = -1;
|
||||||
|
} else {
|
||||||
|
t = new Test();
|
||||||
|
}
|
||||||
|
t.value = new Object();
|
||||||
|
t.next = list;
|
||||||
|
list = t;
|
||||||
|
size += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized Object test(int i) {
|
||||||
|
while (true) {
|
||||||
|
if (_closed) {
|
||||||
|
return null;
|
||||||
|
} else if (size > 0) {
|
||||||
|
return get(i);
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String argv[]) throws Exception {
|
||||||
|
Test t = new Test();
|
||||||
|
int lim = 500000;
|
||||||
|
Object o;
|
||||||
|
for (int j = 0; j < lim; j++) {
|
||||||
|
o = t.test(j&1);
|
||||||
|
if (o == null) {
|
||||||
|
throw new Exception("*** Failed on iteration " + j);
|
||||||
|
}
|
||||||
|
if ((j&1) == 0) {
|
||||||
|
t.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user