# HG changeset patch # User kvn # Date 1216249479 25200 # Node ID 02a35ad4adf8f1fc80b679acedbfa8fc8747b6d6 # Parent 9b66e6287f4acad10b8d498d16077cf4703ec349 6723160: Nightly failure: Error: meet not symmetric Summary: Add missing _instance_id settings and other EA fixes. Reviewed-by: rasbold diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/adlc/formssel.cpp Wed Jul 16 16:04:39 2008 -0700 @@ -3825,6 +3825,8 @@ strcmp(opType,"ConvL2D")==0 || strcmp(opType,"ConvL2F")==0 || strcmp(opType,"ConvL2I")==0 || + strcmp(opType,"DecodeN")==0 || + strcmp(opType,"EncodeP")==0 || strcmp(opType,"RoundDouble")==0 || strcmp(opType,"RoundFloat")==0 || strcmp(opType,"ReverseBytesI")==0 || diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/opto/callnode.cpp Wed Jul 16 16:04:39 2008 -0700 @@ -631,61 +631,13 @@ bool CallNode::may_modify(const TypePtr *addr_t, PhaseTransform *phase) { const TypeOopPtr *adrInst_t = addr_t->isa_oopptr(); - // if not an InstPtr or not an instance type, assume the worst - if (adrInst_t == NULL || !adrInst_t->is_known_instance_field()) { + // If not an OopPtr or not an instance type, assume the worst. + // Note: currently this method is called only for instance types. + if (adrInst_t == NULL || !adrInst_t->is_known_instance()) { return true; } - Compile *C = phase->C; - int offset = adrInst_t->offset(); - 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; - } - } - } - } + // The instance_id is set only for scalar-replaceable allocations which + // are not passed as arguments according to Escape Analysis. return false; } diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/opto/cfgnode.cpp --- a/src/share/vm/opto/cfgnode.cpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/opto/cfgnode.cpp Wed Jul 16 16:04:39 2008 -0700 @@ -713,7 +713,9 @@ assert(type() == Type::MEMORY && (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM || 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"); // Check if an appropriate node already exists. @@ -1089,6 +1091,8 @@ if (rc == NULL || phase->type(rc) == Type::TOP) continue; // ignore unreachable control path Node* n = in(i); + if (n == NULL) + continue; Node* un = n->uncast(); if (un == NULL || un == this || phase->type(un) == Type::TOP) { continue; // ignore if top, or in(i) and "this" are in a data cycle diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/opto/compile.cpp Wed Jul 16 16:04:39 2008 -0700 @@ -999,9 +999,14 @@ int offset = tj->offset(); 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. if (offset == Type::OffsetBot && (tj->isa_instptr() /*|| tj->isa_klassptr()*/)) { assert(InlineUnsafeOps, "indeterminate pointers come only from unsafe ops"); + assert(!is_known_inst, "scalarizable allocation should not have unsafe references"); tj = TypeOopPtr::BOTTOM; ptr = tj->ptr(); offset = tj->offset(); @@ -1009,14 +1014,20 @@ // Array pointers need some flattening 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 // space to include all of the array body. Only the header, klass // and array length can be accessed un-aliased. if( offset != Type::OffsetBot ) { if( ta->const_oop() ) { // methodDataOop or methodOop 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() ) { // range is OK as-is. tj = ta = TypeAryPtr::RANGE; @@ -1030,29 +1041,29 @@ ptr = TypePtr::BotPTR; } else { // Random constant offset 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. if (ta->size() != 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. if (ta->elem()->isa_narrowoop() && ta->elem() != TypeNarrowOop::BOTTOM) { 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) { 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 // cannot be distinguished by bytecode alone. if (ta->elem() == TypeInt::BOOL) { const TypeAry *tary = TypeAry::make(TypeInt::BYTE, ta->size()); 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. // Make sure the Bottom and NotNull variants alias the same. @@ -1072,21 +1083,24 @@ if( ptr == TypePtr::Constant ) { // No constant oop pointers (such as Strings); they alias with // unknown strings. + assert(!is_known_inst, "not scalarizable allocation"); 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 } else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) { // During the 2nd round of IterGVN, NotNull castings are removed. // Make sure the Bottom and NotNull 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 ciInstanceKlass *k = to->klass()->as_instance_klass(); if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) { // First handle header references such as a LoadKlassNode, even if the // 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) { to = NULL; tj = TypeOopPtr::BOTTOM; @@ -1094,7 +1108,11 @@ } else { ciInstanceKlass *canonical_holder = k->get_canonical_holder(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 @@ assert(flat != TypePtr::BOTTOM, "cannot alias-analyze an untyped ptr"); if (flat->isa_oopptr() && !flat->isa_klassptr()) { 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(flat == flatten_alias_type(flat), "exact bit doesn't matter"); diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/opto/escape.cpp Wed Jul 16 16:04:39 2008 -0700 @@ -717,12 +717,17 @@ } } } - if (is_instance && result->is_Phi()) { + if (result->is_Phi()) { PhiNode *mphi = result->as_Phi(); assert(mphi->bottom_type() == Type::MEMORY, "memory phi required"); const TypePtr *t = mphi->adr_type(); 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); + } 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. @@ -859,10 +864,14 @@ !n->is_CheckCastPP()) // not unique CheckCastPP. continue; // 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. + // 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 - && igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeKlassPtr::OBJECT) { + && (alloc->is_AllocateArray() || + igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeKlassPtr::OBJECT)) { Node *cast2 = NULL; for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node *use = n->fast_out(i); @@ -878,7 +887,7 @@ } } 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) // - non-escaping // - eligible to be a unique type @@ -888,7 +897,7 @@ const TypeOopPtr *t = igvn->type(n)->isa_oopptr(); if (t == NULL) 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->set_type(n, tinst); n->raise_bottom_type(tinst); @@ -1204,8 +1213,8 @@ // to recursively process Phi's encounted on the input memory // chains as is done in split_memory_phi() since they will // also be processed here. - while (orig_phis.length() != 0) { - PhiNode *phi = orig_phis.pop(); + for (int j = 0; j < orig_phis.length(); j++) { + PhiNode *phi = orig_phis.at(j); int alias_idx = _compile->get_alias_index(phi->adr_type()); igvn->hash_delete(phi); for (uint i = 1; i < phi->req(); i++) { diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/opto/macro.cpp Wed Jul 16 16:04:39 2008 -0700 @@ -231,8 +231,7 @@ } else { return mem; } - if (mem == orig_mem) - return mem; + assert(mem != orig_mem, "dead memory loop"); } } @@ -241,21 +240,44 @@ // on the input paths. // Note: this function is recursive, its depth is limied by the "level" argument // 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"); + int alias_idx = C->get_alias_index(adr_t); + int offset = adr_t->offset(); + 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; } - int alias_idx = C->get_alias_index(adr_t); - int offset = adr_t->offset(); - int instance_id = adr_t->instance_id(); - Node *start_mem = C->start()->proj_out(TypeFunc::Memory); Node *alloc_mem = alloc->in(TypeFunc::Memory); uint length = mem->req(); GrowableArray 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++) { Node *in = mem->in(j); if (in == NULL || in->is_top()) { @@ -280,33 +302,17 @@ } else if(val->is_Proj() && val->in(0) == alloc) { values.at_put(j, _igvn.zerocon(ft)); } else if (val->is_Phi()) { - // Check if an appropriate node already exists. - Node* region = val->in(0); - Node* old_phi = 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; - } + val = value_from_mem_phi(val, ft, phi_type, adr_t, alloc, value_phis, level-1); + if (val == NULL) { + return NULL; } - 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 { return NULL; // unknown node on this path } } } - // create a new Phi for the value - PhiNode *phi = new (C, length) PhiNode(mem->in(0), phi_type, NULL, instance_id, alias_idx, offset); + // Set Phi's inputs for (uint j = 1; j < length; j++) { if (values.at(j) == mem) { phi->init_req(j, phi); @@ -314,7 +320,6 @@ phi->init_req(j, values.at(j)); } } - transform_later(phi); return phi; } @@ -329,7 +334,8 @@ Node *start_mem = C->start()->proj_out(TypeFunc::Memory); Node *alloc_ctrl = alloc->in(TypeFunc::Control); 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; @@ -389,9 +395,18 @@ return mem->in(MemNode::ValueIn); } else if (mem->is_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) { 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(); + } } } } diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/opto/macro.hpp --- a/src/share/vm/opto/macro.hpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/opto/macro.hpp Wed Jul 16 16:04:39 2008 -0700 @@ -79,7 +79,7 @@ const TypeFunc* slow_call_type, 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_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 can_eliminate_allocation(AllocateNode *alloc, GrowableArray & safepoints); diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/opto/memnode.cpp Wed Jul 16 16:04:39 2008 -0700 @@ -135,7 +135,9 @@ const TypePtr *t = mphi->adr_type(); if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM || 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 result = mphi->split_out_instance(t_adr, igvn); } else { diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/opto/node.hpp Wed Jul 16 16:04:39 2008 -0700 @@ -1399,6 +1399,10 @@ uint index() const { 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) { _inode_top->node = n; } diff -r 9b66e6287f4a -r 02a35ad4adf8 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Wed Jul 16 10:08:57 2008 -0700 +++ b/src/share/vm/opto/type.cpp Wed Jul 16 16:04:39 2008 -0700 @@ -2218,7 +2218,7 @@ return make(ptr, _offset); } -//-----------------------------cast_to_instance------------------------------- +//-----------------------------cast_to_instance_id---------------------------- const TypeOopPtr *TypeOopPtr::cast_to_instance_id(int instance_id) const { // There are no instances of a general oop. // Return self unchanged. @@ -2610,8 +2610,7 @@ // Ptr is never Null assert( ptr != Null, "NULL pointers are not typed" ); - if ( instance_id > 0 ) - xk = true; // instances are always exactly typed + assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed"); if (!UseExactTypes) xk = false; if (ptr == Constant) { // Note: This case includes meta-object constants, such as methods. @@ -2650,16 +2649,10 @@ 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 { if( instance_id == _instance_id ) return this; - bool exact = _klass_is_exact; - 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); + return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id); } //------------------------------xmeet_unloaded--------------------------------- @@ -2899,6 +2892,7 @@ xk = above_centerline(ptr) ? tinst_xk : false; // Watch out for Constant vs. AnyNull interface. if (ptr == Constant) ptr = NotNull; // forget it was a constant + instance_id = InstanceBot; } ciObject* o = NULL; // the Constant value, if any if (ptr == Constant) { @@ -2989,6 +2983,7 @@ // class hierarchy - which means we have to fall to at least NotNull. if( ptr == TopPTR || ptr == AnyNull || ptr == Constant ) ptr = NotNull; + instance_id = InstanceBot; // Now we find the LCA of Java classes ciKlass* k = this_klass->least_common_ancestor(tinst_klass); @@ -3101,8 +3096,7 @@ assert(!(k == NULL && ary->_elem->isa_int()), "integral arrays must be pre-equipped with a class"); if (!xk) xk = ary->ary_must_be_exact(); - if ( instance_id > 0 ) - xk = true; // instances are always exactly typed + assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed"); if (!UseExactTypes) xk = (ptr == Constant); return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id))->hashcons(); } @@ -3113,8 +3107,7 @@ "integral arrays must be pre-equipped with a class"); assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" ); if (!xk) xk = (o != NULL) || ary->ary_must_be_exact(); - if ( instance_id > 0 ) - xk = true; // instances are always exactly typed + assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed"); if (!UseExactTypes) xk = (ptr == Constant); return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id))->hashcons(); } @@ -3134,16 +3127,10 @@ 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 { if( instance_id == _instance_id ) return this; - bool exact = _klass_is_exact; - 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); + return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id); } //-----------------------------narrow_size_type------------------------------- @@ -3300,6 +3287,7 @@ } else { // Something like byte[int+] meets char[int+]. // This must fall to bottom, not (int[-128..65535])[int+]. + instance_id = InstanceBot; tary = TypeAry::make(Type::BOTTOM, tary->_size); } } @@ -3316,6 +3304,7 @@ if( tap->const_oop() != NULL && !o->equals(tap->const_oop()) ) { ptr = NotNull; o = NULL; + instance_id = InstanceBot; } } else if( above_centerline(_ptr) ) { o = tap->const_oop(); diff -r 9b66e6287f4a -r 02a35ad4adf8 test/compiler/6724218/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6724218/Test.java Wed Jul 16 16:04:39 2008 -0700 @@ -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(); + } + } + } +}