# HG changeset patch # User kvn # Date 1320705237 28800 # Node ID 85bcf8ef9cc83dc929c04c85dfb3d35fd21a8e60 # Parent 31a7be6a8ef8d4069e4b1a8b333468b7b79b4c31 7059047: EA: can't find initializing store with several CheckCastPP Summary: Split adjust_escape_state() method into two methods to find initializing stores. Reviewed-by: never diff -r 31a7be6a8ef8 -r 85bcf8ef9cc8 hotspot/src/share/vm/opto/escape.cpp --- a/hotspot/src/share/vm/opto/escape.cpp Fri Nov 04 13:55:31 2011 -0700 +++ b/hotspot/src/share/vm/opto/escape.cpp Mon Nov 07 14:33:57 2011 -0800 @@ -378,16 +378,17 @@ // whose offset matches "offset". void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) { PointsToNode* an = ptnode_adr(adr_i); + bool is_alloc = an->_node->is_Allocate(); for (uint fe = 0; fe < an->edge_count(); fe++) { assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); int fi = an->edge_target(fe); PointsToNode* pf = ptnode_adr(fi); - int po = pf->offset(); - if (pf->edge_count() == 0) { - // we have not seen any stores to this field, assume it was set outside this method + int offset = pf->offset(); + if (!is_alloc) { + // Assume the field was set outside this method if it is not Allocation add_pointsto_edge(fi, _phantom_object); } - if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { + if (offset == offs || offset == Type::OffsetBot || offs == Type::OffsetBot) { add_deferred_edge(from_i, fi); } } @@ -1041,7 +1042,7 @@ PointsToNode::EscapeState es = escape_state(alloc); // We have an allocation or call which returns a Java object, // see if it is unescaped. - if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable) + if (es != PointsToNode::NoEscape || !ptn->scalar_replaceable()) continue; // Find CheckCastPP for the allocate or for the return value of a call @@ -1090,7 +1091,7 @@ // so it could be eliminated. alloc->as_Allocate()->_is_scalar_replaceable = true; } - set_escape_state(n->_idx, es); + set_escape_state(n->_idx, es); // CheckCastPP escape state // in order for an object to be scalar-replaceable, it must be: // - a direct allocation (not a call returning an object) // - non-escaping @@ -1102,15 +1103,14 @@ set_map(n->_idx, alloc); const TypeOopPtr *t = igvn->type(n)->isa_oopptr(); if (t == NULL) - continue; // not a TypeInstPtr + continue; // not a TypeOopPtr 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); igvn->hash_insert(n); record_for_optimizer(n); - if (alloc->is_Allocate() && ptn->_scalar_replaceable && - (t->isa_instptr() || t->isa_aryptr())) { + if (alloc->is_Allocate() && (t->isa_instptr() || t->isa_aryptr())) { // First, put on the worklist all Field edges from Connection Graph // which is more accurate then putting immediate users from Ideal Graph. @@ -1538,7 +1538,8 @@ worklist_init.push(C->root()); } - GrowableArray cg_worklist; + GrowableArray alloc_worklist; + GrowableArray addp_worklist; PhaseGVN* igvn = _igvn; bool has_allocations = false; @@ -1551,11 +1552,13 @@ if (n->is_Allocate() || n->is_CallStaticJava() && ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { has_allocations = true; + if (n->is_Allocate()) + alloc_worklist.append(n); } if(n->is_AddP()) { // Collect address nodes. Use them during stage 3 below // to build initial connection graph field edges. - cg_worklist.append(n->_idx); + addp_worklist.append(n); } else if (n->is_MergeMem()) { // Collect all MergeMem nodes to add memory slices for // scalar replaceable objects in split_unique_types(). @@ -1581,10 +1584,9 @@ // 3. Pass to create initial fields edges (JavaObject -F-> AddP) // to reduce number of iterations during stage 4 below. - uint cg_length = cg_worklist.length(); - for( uint next = 0; next < cg_length; ++next ) { - int ni = cg_worklist.at(next); - Node* n = ptnode_adr(ni)->_node; + uint addp_length = addp_worklist.length(); + for( uint next = 0; next < addp_length; ++next ) { + Node* n = addp_worklist.at(next); Node* base = get_addp_base(n); if (base->is_Proj()) base = base->in(0); @@ -1594,7 +1596,7 @@ } } - cg_worklist.clear(); + GrowableArray cg_worklist; cg_worklist.append(_phantom_object); GrowableArray worklist; @@ -1653,73 +1655,44 @@ Arena* arena = Thread::current()->resource_area(); VectorSet visited(arena); + + // 5. Find fields initializing values for not escaped allocations + uint alloc_length = alloc_worklist.length(); + for (uint next = 0; next < alloc_length; ++next) { + Node* n = alloc_worklist.at(next); + if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) { + find_init_values(n, &visited, igvn); + } + } + worklist.clear(); - // 5. Remove deferred edges from the graph and adjust - // escape state of nonescaping objects. - cg_length = cg_worklist.length(); - for( uint next = 0; next < cg_length; ++next ) { + // 6. Remove deferred edges from the graph. + uint cg_length = cg_worklist.length(); + for (uint next = 0; next < cg_length; ++next) { int ni = cg_worklist.at(next); PointsToNode* ptn = ptnode_adr(ni); PointsToNode::NodeType nt = ptn->node_type(); if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { remove_deferred(ni, &worklist, &visited); Node *n = ptn->_node; - if (n->is_AddP()) { - // Search for objects which are not scalar replaceable - // and adjust their escape state. - adjust_escape_state(ni, igvn); - } } } - // 6. Propagate escape states. - worklist.clear(); - bool has_non_escaping_obj = false; - - // push all GlobalEscape nodes on the worklist - for( uint next = 0; next < cg_length; ++next ) { - int nk = cg_worklist.at(next); - if (ptnode_adr(nk)->escape_state() == PointsToNode::GlobalEscape) - worklist.push(nk); - } - // mark all nodes reachable from GlobalEscape nodes - while(worklist.length() > 0) { - PointsToNode* ptn = ptnode_adr(worklist.pop()); - uint e_cnt = ptn->edge_count(); - for (uint ei = 0; ei < e_cnt; ei++) { - uint npi = ptn->edge_target(ei); - PointsToNode *np = ptnode_adr(npi); - if (np->escape_state() < PointsToNode::GlobalEscape) { - set_escape_state(npi, PointsToNode::GlobalEscape); - worklist.push(npi); - } - } + // 7. Adjust escape state of nonescaping objects. + for (uint next = 0; next < addp_length; ++next) { + Node* n = addp_worklist.at(next); + adjust_escape_state(n); } - // push all ArgEscape nodes on the worklist - for( uint next = 0; next < cg_length; ++next ) { - int nk = cg_worklist.at(next); - if (ptnode_adr(nk)->escape_state() == PointsToNode::ArgEscape) - worklist.push(nk); - } + // 8. Propagate escape states. + worklist.clear(); + + // mark all nodes reachable from GlobalEscape nodes + (void)propagate_escape_state(&cg_worklist, &worklist, PointsToNode::GlobalEscape); + // mark all nodes reachable from ArgEscape nodes - while(worklist.length() > 0) { - PointsToNode* ptn = ptnode_adr(worklist.pop()); - if (ptn->node_type() == PointsToNode::JavaObject) - has_non_escaping_obj = true; // Non GlobalEscape - uint e_cnt = ptn->edge_count(); - for (uint ei = 0; ei < e_cnt; ei++) { - uint npi = ptn->edge_target(ei); - PointsToNode *np = ptnode_adr(npi); - if (np->escape_state() < PointsToNode::ArgEscape) { - set_escape_state(npi, PointsToNode::ArgEscape); - worklist.push(npi); - } - } - } - - GrowableArray alloc_worklist; + bool has_non_escaping_obj = propagate_escape_state(&cg_worklist, &worklist, PointsToNode::ArgEscape); // push all NoEscape nodes on the worklist for( uint next = 0; next < cg_length; ++next ) { @@ -1727,6 +1700,7 @@ if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape) worklist.push(nk); } + alloc_worklist.clear(); // mark all nodes reachable from NoEscape nodes while(worklist.length() > 0) { uint nk = worklist.pop(); @@ -1735,9 +1709,11 @@ !(nk == _noop_null || nk == _oop_null)) has_non_escaping_obj = true; // Non Escape Node* n = ptn->_node; - if (n->is_Allocate() && ptn->_scalar_replaceable ) { + bool scalar_replaceable = ptn->scalar_replaceable(); + if (n->is_Allocate() && scalar_replaceable) { // Push scalar replaceable allocations on alloc_worklist - // for processing in split_unique_types(). + // for processing in split_unique_types(). Note, + // following code may change scalar_replaceable value. alloc_worklist.append(n); } uint e_cnt = ptn->edge_count(); @@ -1746,6 +1722,13 @@ PointsToNode *np = ptnode_adr(npi); if (np->escape_state() < PointsToNode::NoEscape) { set_escape_state(npi, PointsToNode::NoEscape); + if (!scalar_replaceable) { + np->set_scalar_replaceable(false); + } + worklist.push(npi); + } else if (np->scalar_replaceable() && !scalar_replaceable) { + // Propagate scalar_replaceable value. + np->set_scalar_replaceable(false); worklist.push(npi); } } @@ -1759,7 +1742,7 @@ assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape, "sanity"); } - if (EliminateLocks) { + if (EliminateLocks && has_non_escaping_obj) { // Mark locks before changing ideal graph. int cnt = C->macro_count(); for( int i=0; i < cnt; i++ ) { @@ -1784,7 +1767,18 @@ } #endif - bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0; + bool has_scalar_replaceable_candidates = false; + alloc_length = alloc_worklist.length(); + for (uint next = 0; next < alloc_length; ++next) { + Node* n = alloc_worklist.at(next); + PointsToNode* ptn = ptnode_adr(n->_idx); + assert(ptn->escape_state() == PointsToNode::NoEscape, "sanity"); + if (ptn->scalar_replaceable()) { + has_scalar_replaceable_candidates = true; + break; + } + } + if ( has_scalar_replaceable_candidates && C->AliasLevel() >= 3 && EliminateAllocations ) { @@ -1813,53 +1807,32 @@ return has_non_escaping_obj; } -// Adjust escape state after Connection Graph is built. -void ConnectionGraph::adjust_escape_state(int nidx, PhaseTransform* phase) { - PointsToNode* ptn = ptnode_adr(nidx); - Node* n = ptn->_node; - assert(n->is_AddP(), "Should be called for AddP nodes only"); - // Search for objects which are not scalar replaceable. - // Mark their escape state as ArgEscape to propagate the state - // to referenced objects. - // Note: currently there are no difference in compiler optimizations - // for ArgEscape objects and NoEscape objects which are not - // scalar replaceable. +// Find fields initializing values for allocations. +void ConnectionGraph::find_init_values(Node* alloc, VectorSet* visited, PhaseTransform* phase) { + assert(alloc->is_Allocate(), "Should be called for Allocate nodes only"); + PointsToNode* pta = ptnode_adr(alloc->_idx); + assert(pta->escape_state() == PointsToNode::NoEscape, "Not escaped Allocate nodes only"); + InitializeNode* ini = alloc->as_Allocate()->initialization(); Compile* C = _compile; - - int offset = ptn->offset(); - Node* base = get_addp_base(n); - VectorSet* ptset = PointsTo(base); - int ptset_size = ptset->Size(); - + visited->Reset(); // Check if a oop field's initializing value is recorded and add // a corresponding NULL field's value if it is not recorded. // Connection Graph does not record a default initialization by NULL // captured by Initialize node. // - // Note: it will disable scalar replacement in some cases: - // - // Point p[] = new Point[1]; - // p[0] = new Point(); // Will be not scalar replaced - // - // but it will save us from incorrect optimizations in next cases: - // - // Point p[] = new Point[1]; - // if ( x ) p[0] = new Point(); // Will be not scalar replaced - // - // Do a simple control flow analysis to distinguish above cases. - // - if (offset != Type::OffsetBot && ptset_size == 1) { - uint elem = ptset->getelem(); // Allocation node's index - // It does not matter if it is not Allocation node since - // only non-escaping allocations are scalar replaced. - if (ptnode_adr(elem)->_node->is_Allocate() && - ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) { - AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate(); - InitializeNode* ini = alloc->initialization(); + uint ae_cnt = pta->edge_count(); + for (uint ei = 0; ei < ae_cnt; ei++) { + uint nidx = pta->edge_target(ei); // Field (AddP) + PointsToNode* ptn = ptnode_adr(nidx); + assert(ptn->_node->is_AddP(), "Should be AddP nodes only"); + int offset = ptn->offset(); + if (offset != Type::OffsetBot && + offset != oopDesc::klass_offset_in_bytes() && + !visited->test_set(offset)) { // Check only oop fields. - const Type* adr_type = n->as_AddP()->bottom_type(); + const Type* adr_type = ptn->_node->as_AddP()->bottom_type(); BasicType basic_field_type = T_INT; if (adr_type->isa_instptr()) { ciField* field = C->alias_type(adr_type->isa_instptr())->field(); @@ -1869,12 +1842,20 @@ // Ignore non field load (for example, klass load) } } else if (adr_type->isa_aryptr()) { - const Type* elemtype = adr_type->isa_aryptr()->elem(); - basic_field_type = elemtype->array_element_basic_type(); + if (offset != arrayOopDesc::length_offset_in_bytes()) { + const Type* elemtype = adr_type->isa_aryptr()->elem(); + basic_field_type = elemtype->array_element_basic_type(); + } else { + // Ignore array length load + } +#ifdef ASSERT } else { - // Raw pointers are used for initializing stores so skip it. + // Raw pointers are used for initializing stores so skip it + // since it should be recorded already + Node* base = get_addp_base(ptn->_node); assert(adr_type->isa_rawptr() && base->is_Proj() && (base->in(0) == alloc),"unexpected pointer type"); +#endif } if (basic_field_type == T_OBJECT || basic_field_type == T_NARROWOOP || @@ -1889,18 +1870,33 @@ // Check for a store which follows allocation without branches. // For example, a volatile field store is not collected // by Initialize node. TODO: it would be nice to use idom() here. - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - store = n->fast_out(i); - if (store->is_Store() && store->in(0) != NULL) { - Node* ctrl = store->in(0); - while(!(ctrl == ini || ctrl == alloc || ctrl == NULL || - ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() || - ctrl->is_IfTrue() || ctrl->is_IfFalse())) { - ctrl = ctrl->in(0); - } - if (ctrl == ini || ctrl == alloc) { - value = store->in(MemNode::ValueIn); - break; + // + // Search all references to the same field which use different + // AddP nodes, for example, in the next case: + // + // Point p[] = new Point[1]; + // if ( x ) { p[0] = new Point(); p[0].x = x; } + // if ( p[0] != null ) { y = p[0].x; } // has CastPP + // + for (uint next = ei; (next < ae_cnt) && (value == NULL); next++) { + uint fpi = pta->edge_target(next); // Field (AddP) + PointsToNode *ptf = ptnode_adr(fpi); + if (ptf->offset() == offset) { + Node* nf = ptf->_node; + for (DUIterator_Fast imax, i = nf->fast_outs(imax); i < imax; i++) { + store = nf->fast_out(i); + if (store->is_Store() && store->in(0) != NULL) { + Node* ctrl = store->in(0); + while(!(ctrl == ini || ctrl == alloc || ctrl == NULL || + ctrl == C->root() || ctrl == C->top() || ctrl->is_Region() || + ctrl->is_IfTrue() || ctrl->is_IfFalse())) { + ctrl = ctrl->in(0); + } + if (ctrl == ini || ctrl == alloc) { + value = store->in(MemNode::ValueIn); + break; + } + } } } } @@ -1909,21 +1905,35 @@ if (value == NULL || value != ptnode_adr(value->_idx)->_node) { // A field's initializing value was not recorded. Add NULL. uint null_idx = UseCompressedOops ? _noop_null : _oop_null; - add_pointsto_edge(nidx, null_idx); + add_edge_from_fields(alloc->_idx, null_idx, offset); } } } } +} + +// Adjust escape state after Connection Graph is built. +void ConnectionGraph::adjust_escape_state(Node* n) { + PointsToNode* ptn = ptnode_adr(n->_idx); + assert(n->is_AddP(), "Should be called for AddP nodes only"); + // Search for objects which are not scalar replaceable + // and mark them to propagate the state to referenced objects. + // + + int offset = ptn->offset(); + Node* base = get_addp_base(n); + VectorSet* ptset = PointsTo(base); + int ptset_size = ptset->Size(); // An object is not scalar replaceable if the field which may point // to it has unknown offset (unknown element of an array of objects). // + if (offset == Type::OffsetBot) { uint e_cnt = ptn->edge_count(); for (uint ei = 0; ei < e_cnt; ei++) { uint npi = ptn->edge_target(ei); - set_escape_state(npi, PointsToNode::ArgEscape); - ptnode_adr(npi)->_scalar_replaceable = false; + ptnode_adr(npi)->set_scalar_replaceable(false); } } @@ -1942,20 +1952,62 @@ // to unknown field (unknown element for arrays, offset is OffsetBot). // // Or the address may point to more then one object. This may produce - // the false positive result (set scalar_replaceable to false) + // the false positive result (set not scalar replaceable) // since the flow-insensitive escape analysis can't separate // the case when stores overwrite the field's value from the case // when stores happened on different control branches. // + // Note: it will disable scalar replacement in some cases: + // + // Point p[] = new Point[1]; + // p[0] = new Point(); // Will be not scalar replaced + // + // but it will save us from incorrect optimizations in next cases: + // + // Point p[] = new Point[1]; + // if ( x ) p[0] = new Point(); // Will be not scalar replaced + // if (ptset_size > 1 || ptset_size != 0 && (has_LoadStore || offset == Type::OffsetBot)) { for( VectorSetI j(ptset); j.test(); ++j ) { - set_escape_state(j.elem, PointsToNode::ArgEscape); - ptnode_adr(j.elem)->_scalar_replaceable = false; + ptnode_adr(j.elem)->set_scalar_replaceable(false); } } } +// Propagate escape states to referenced nodes. +bool ConnectionGraph::propagate_escape_state(GrowableArray* cg_worklist, + GrowableArray* worklist, + PointsToNode::EscapeState esc_state) { + bool has_java_obj = false; + + // push all nodes with the same escape state on the worklist + uint cg_length = cg_worklist->length(); + for (uint next = 0; next < cg_length; ++next) { + int nk = cg_worklist->at(next); + if (ptnode_adr(nk)->escape_state() == esc_state) + worklist->push(nk); + } + // mark all reachable nodes + while (worklist->length() > 0) { + PointsToNode* ptn = ptnode_adr(worklist->pop()); + if (ptn->node_type() == PointsToNode::JavaObject) { + has_java_obj = true; + } + uint e_cnt = ptn->edge_count(); + for (uint ei = 0; ei < e_cnt; ei++) { + uint npi = ptn->edge_target(ei); + PointsToNode *np = ptnode_adr(npi); + if (np->escape_state() < esc_state) { + set_escape_state(npi, esc_state); + worklist->push(npi); + } + } + } + // Has not escaping java objects + return has_java_obj && (esc_state < PointsToNode::GlobalEscape); +} + void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { switch (call->Opcode()) { @@ -2112,6 +2164,7 @@ } else { es = PointsToNode::NoEscape; edge_to = call_idx; + assert(ptnode_adr(call_idx)->scalar_replaceable(), "sanity"); } set_escape_state(call_idx, es); add_pointsto_edge(resproj_idx, edge_to); @@ -2135,10 +2188,11 @@ } else { es = PointsToNode::NoEscape; edge_to = call_idx; + assert(ptnode_adr(call_idx)->scalar_replaceable(), "sanity"); int length = call->in(AllocateNode::ALength)->find_int_con(-1); if (length < 0 || length > EliminateAllocationArraySizeLimit) { // Not scalar replaceable if the length is not constant or too big. - ptnode_adr(call_idx)->_scalar_replaceable = false; + ptnode_adr(call_idx)->set_scalar_replaceable(false); } } set_escape_state(call_idx, es); @@ -2180,11 +2234,12 @@ // Mark it as NoEscape so that objects referenced by // it's fields will be marked as NoEscape at least. set_escape_state(call_idx, PointsToNode::NoEscape); + ptnode_adr(call_idx)->set_scalar_replaceable(false); add_pointsto_edge(resproj_idx, call_idx); copy_dependencies = true; } else if (call_analyzer->is_return_local()) { // determine whether any arguments are returned - set_escape_state(call_idx, PointsToNode::NoEscape); + set_escape_state(call_idx, PointsToNode::ArgEscape); bool ret_arg = false; for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { const Type* at = d->field_at(i); @@ -2201,7 +2256,6 @@ add_pointsto_edge(resproj_idx, arg->_idx); else add_deferred_edge(resproj_idx, arg->_idx); - arg_esp->_hidden_alias = true; } } } @@ -2210,18 +2264,12 @@ set_escape_state(call_idx, PointsToNode::GlobalEscape); add_pointsto_edge(resproj_idx, _phantom_object); } - copy_dependencies = true; + if (done) { + copy_dependencies = true; + } } else { set_escape_state(call_idx, PointsToNode::GlobalEscape); add_pointsto_edge(resproj_idx, _phantom_object); - for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { - const Type* at = d->field_at(i); - if (at->isa_oopptr() != NULL) { - Node *arg = call->in(i)->uncast(); - PointsToNode *arg_esp = ptnode_adr(arg->_idx); - arg_esp->_hidden_alias = true; - } - } } if (copy_dependencies) call_analyzer->copy_dependencies(_compile->dependencies()); diff -r 31a7be6a8ef8 -r 85bcf8ef9cc8 hotspot/src/share/vm/opto/escape.hpp --- a/hotspot/src/share/vm/opto/escape.hpp Fri Nov 04 13:55:31 2011 -0700 +++ b/hotspot/src/share/vm/opto/escape.hpp Mon Nov 07 14:33:57 2011 -0800 @@ -74,7 +74,7 @@ // C2 does not have local variables. However for the purposes of constructing // the connection graph, the following IR nodes are treated as local variables: // Phi (pointer values) -// LoadP +// LoadP, LoadN // Proj#5 (value returned from callnodes including allocations) // CheckCastPP, CastPP // @@ -84,7 +84,7 @@ // // The following node types are JavaObject: // -// top() +// phantom_object (general globally escaped object) // Allocate // AllocateArray // Parm (for incoming arguments) @@ -93,6 +93,7 @@ // ConP // LoadKlass // ThreadLocal +// CallStaticJava (which returns Object) // // AddP nodes are fields. // @@ -130,10 +131,12 @@ typedef enum { UnknownEscape = 0, - NoEscape = 1, // A scalar replaceable object with unique type. - ArgEscape = 2, // An object passed as argument or referenced by - // argument (and not globally escape during call). - GlobalEscape = 3 // An object escapes the method and thread. + NoEscape = 1, // An object does not escape method or thread and it is + // not passed to call. It could be replaced with scalar. + ArgEscape = 2, // An object does not escape method or thread but it is + // passed as argument to call or referenced by argument + // and it does not escape during call. + GlobalEscape = 3 // An object escapes the method or thread. } EscapeState; typedef enum { @@ -153,28 +156,25 @@ NodeType _type; EscapeState _escape; - GrowableArray* _edges; // outgoing edges + GrowableArray* _edges; // outgoing edges + Node* _node; // Ideal node corresponding to this PointsTo node. + int _offset; // Object fields offsets. + bool _scalar_replaceable; // Not escaped object could be replaced with scalar public: - Node* _node; // Ideal node corresponding to this PointsTo node. - int _offset; // Object fields offsets. - bool _scalar_replaceable;// Not escaped object could be replaced with scalar - bool _hidden_alias; // This node is an argument to a function. - // which may return it creating a hidden alias. - PointsToNode(): _type(UnknownType), _escape(UnknownEscape), _edges(NULL), _node(NULL), _offset(-1), - _scalar_replaceable(true), - _hidden_alias(false) {} + _scalar_replaceable(true) {} EscapeState escape_state() const { return _escape; } NodeType node_type() const { return _type;} int offset() { return _offset;} + bool scalar_replaceable() { return _scalar_replaceable;} void set_offset(int offs) { _offset = offs;} void set_escape_state(EscapeState state) { _escape = state; } @@ -182,6 +182,7 @@ assert(_type == UnknownType || _type == ntype, "Can't change node type"); _type = ntype; } + void set_scalar_replaceable(bool v) { _scalar_replaceable = v; } // count of outgoing edges uint edge_count() const { return (_edges == NULL) ? 0 : _edges->length(); } @@ -233,8 +234,8 @@ // that pointer values loaded from // a field which has not been set // are assumed to point to. - uint _oop_null; // ConP(#NULL) - uint _noop_null; // ConN(#NULL) + uint _oop_null; // ConP(#NULL)->_idx + uint _noop_null; // ConN(#NULL)->_idx Compile * _compile; // Compile object for current compilation PhaseIterGVN * _igvn; // Value numbering @@ -339,8 +340,16 @@ // Set the escape state of a node void set_escape_state(uint ni, PointsToNode::EscapeState es); + // Find fields initializing values for allocations. + void find_init_values(Node* n, VectorSet* visited, PhaseTransform* phase); + // Adjust escape state after Connection Graph is built. - void adjust_escape_state(int nidx, PhaseTransform* phase); + void adjust_escape_state(Node* n); + + // Propagate escape states to referenced nodes. + bool propagate_escape_state(GrowableArray* cg_worklist, + GrowableArray* worklist, + PointsToNode::EscapeState esc_state); // Compute the escape information bool compute_escape(); @@ -357,21 +366,6 @@ // escape state of a node PointsToNode::EscapeState escape_state(Node *n); - // other information we have collected - bool is_scalar_replaceable(Node *n) { - if (_collecting || (n->_idx >= nodes_size())) - return false; - PointsToNode* ptn = ptnode_adr(n->_idx); - return ptn->escape_state() == PointsToNode::NoEscape && ptn->_scalar_replaceable; - } - - bool hidden_alias(Node *n) { - if (_collecting || (n->_idx >= nodes_size())) - return true; - PointsToNode* ptn = ptnode_adr(n->_idx); - return (ptn->escape_state() != PointsToNode::NoEscape) || ptn->_hidden_alias; - } - #ifndef PRODUCT void dump(); #endif