| 1 | /* | 
|---|
| 2 | * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. | 
|---|
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|---|
| 4 | * | 
|---|
| 5 | * This code is free software; you can redistribute it and/or modify it | 
|---|
| 6 | * under the terms of the GNU General Public License version 2 only, as | 
|---|
| 7 | * published by the Free Software Foundation. | 
|---|
| 8 | * | 
|---|
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT | 
|---|
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|---|
| 11 | * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|---|
| 12 | * version 2 for more details (a copy is included in the LICENSE file that | 
|---|
| 13 | * accompanied this code). | 
|---|
| 14 | * | 
|---|
| 15 | * You should have received a copy of the GNU General Public License version | 
|---|
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, | 
|---|
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|---|
| 18 | * | 
|---|
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|---|
| 20 | * or visit www.oracle.com if you need additional information or have any | 
|---|
| 21 | * questions. | 
|---|
| 22 | * | 
|---|
| 23 | */ | 
|---|
| 24 |  | 
|---|
| 25 | #ifndef SHARE_OPTO_ESCAPE_HPP | 
|---|
| 26 | #define SHARE_OPTO_ESCAPE_HPP | 
|---|
| 27 |  | 
|---|
| 28 | #include "opto/addnode.hpp" | 
|---|
| 29 | #include "opto/node.hpp" | 
|---|
| 30 | #include "utilities/growableArray.hpp" | 
|---|
| 31 |  | 
|---|
| 32 | // | 
|---|
| 33 | // Adaptation for C2 of the escape analysis algorithm described in: | 
|---|
| 34 | // | 
|---|
| 35 | // [Choi99] Jong-Deok Shoi, Manish Gupta, Mauricio Seffano, | 
|---|
| 36 | //          Vugranam C. Sreedhar, Sam Midkiff, | 
|---|
| 37 | //          "Escape Analysis for Java", Procedings of ACM SIGPLAN | 
|---|
| 38 | //          OOPSLA  Conference, November 1, 1999 | 
|---|
| 39 | // | 
|---|
| 40 | // The flow-insensitive analysis described in the paper has been implemented. | 
|---|
| 41 | // | 
|---|
| 42 | // The analysis requires construction of a "connection graph" (CG) for | 
|---|
| 43 | // the method being analyzed.  The nodes of the connection graph are: | 
|---|
| 44 | // | 
|---|
| 45 | //     -  Java objects (JO) | 
|---|
| 46 | //     -  Local variables (LV) | 
|---|
| 47 | //     -  Fields of an object (OF),  these also include array elements | 
|---|
| 48 | // | 
|---|
| 49 | // The CG contains 3 types of edges: | 
|---|
| 50 | // | 
|---|
| 51 | //   -  PointsTo  (-P>)    {LV, OF} to JO | 
|---|
| 52 | //   -  Deferred  (-D>)    from {LV, OF} to {LV, OF} | 
|---|
| 53 | //   -  Field     (-F>)    from JO to OF | 
|---|
| 54 | // | 
|---|
| 55 | // The following  utility functions is used by the algorithm: | 
|---|
| 56 | // | 
|---|
| 57 | //   PointsTo(n) - n is any CG node, it returns the set of JO that n could | 
|---|
| 58 | //                 point to. | 
|---|
| 59 | // | 
|---|
| 60 | // The algorithm describes how to construct the connection graph | 
|---|
| 61 | // in the following 4 cases: | 
|---|
| 62 | // | 
|---|
| 63 | //          Case                  Edges Created | 
|---|
| 64 | // | 
|---|
| 65 | // (1)   p   = new T()              LV -P> JO | 
|---|
| 66 | // (2)   p   = q                    LV -D> LV | 
|---|
| 67 | // (3)   p.f = q                    JO -F> OF,  OF -D> LV | 
|---|
| 68 | // (4)   p   = q.f                  JO -F> OF,  LV -D> OF | 
|---|
| 69 | // | 
|---|
| 70 | // In all these cases, p and q are local variables.  For static field | 
|---|
| 71 | // references, we can construct a local variable containing a reference | 
|---|
| 72 | // to the static memory. | 
|---|
| 73 | // | 
|---|
| 74 | // C2 does not have local variables.  However for the purposes of constructing | 
|---|
| 75 | // the connection graph, the following IR nodes are treated as local variables: | 
|---|
| 76 | //     Phi    (pointer values) | 
|---|
| 77 | //     LoadP, LoadN | 
|---|
| 78 | //     Proj#5 (value returned from callnodes including allocations) | 
|---|
| 79 | //     CheckCastPP, CastPP | 
|---|
| 80 | // | 
|---|
| 81 | // The LoadP, Proj and CheckCastPP behave like variables assigned to only once. | 
|---|
| 82 | // Only a Phi can have multiple assignments.  Each input to a Phi is treated | 
|---|
| 83 | // as an assignment to it. | 
|---|
| 84 | // | 
|---|
| 85 | // The following node types are JavaObject: | 
|---|
| 86 | // | 
|---|
| 87 | //     phantom_object (general globally escaped object) | 
|---|
| 88 | //     Allocate | 
|---|
| 89 | //     AllocateArray | 
|---|
| 90 | //     Parm  (for incoming arguments) | 
|---|
| 91 | //     CastX2P ("unsafe" operations) | 
|---|
| 92 | //     CreateEx | 
|---|
| 93 | //     ConP | 
|---|
| 94 | //     LoadKlass | 
|---|
| 95 | //     ThreadLocal | 
|---|
| 96 | //     CallStaticJava (which returns Object) | 
|---|
| 97 | // | 
|---|
| 98 | // AddP nodes are fields. | 
|---|
| 99 | // | 
|---|
| 100 | // After building the graph, a pass is made over the nodes, deleting deferred | 
|---|
| 101 | // nodes and copying the edges from the target of the deferred edge to the | 
|---|
| 102 | // source.  This results in a graph with no deferred edges, only: | 
|---|
| 103 | // | 
|---|
| 104 | //    LV -P> JO | 
|---|
| 105 | //    OF -P> JO (the object whose oop is stored in the field) | 
|---|
| 106 | //    JO -F> OF | 
|---|
| 107 | // | 
|---|
| 108 | // Then, for each node which is GlobalEscape, anything it could point to | 
|---|
| 109 | // is marked GlobalEscape.  Finally, for any node marked ArgEscape, anything | 
|---|
| 110 | // it could point to is marked ArgEscape. | 
|---|
| 111 | // | 
|---|
| 112 |  | 
|---|
| 113 | class  Compile; | 
|---|
| 114 | class  Node; | 
|---|
| 115 | class  CallNode; | 
|---|
| 116 | class  PhiNode; | 
|---|
| 117 | class  PhaseTransform; | 
|---|
| 118 | class  PointsToNode; | 
|---|
| 119 | class  Type; | 
|---|
| 120 | class  TypePtr; | 
|---|
| 121 | class  VectorSet; | 
|---|
| 122 |  | 
|---|
| 123 | class JavaObjectNode; | 
|---|
| 124 | class LocalVarNode; | 
|---|
| 125 | class FieldNode; | 
|---|
| 126 | class ArraycopyNode; | 
|---|
| 127 |  | 
|---|
| 128 | class ConnectionGraph; | 
|---|
| 129 |  | 
|---|
| 130 | // ConnectionGraph nodes | 
|---|
| 131 | class PointsToNode : public ResourceObj { | 
|---|
| 132 | GrowableArray<PointsToNode*> _edges; // List of nodes this node points to | 
|---|
| 133 | GrowableArray<PointsToNode*> _uses;  // List of nodes which point to this node | 
|---|
| 134 |  | 
|---|
| 135 | const u1           _type;  // NodeType | 
|---|
| 136 | u1                _flags;  // NodeFlags | 
|---|
| 137 | u1               _escape;  // EscapeState of object | 
|---|
| 138 | u1        _fields_escape;  // EscapeState of object's fields | 
|---|
| 139 |  | 
|---|
| 140 | Node* const        _node;  // Ideal node corresponding to this PointsTo node. | 
|---|
| 141 | const int           _idx;  // Cached ideal node's _idx | 
|---|
| 142 | const uint         _pidx;  // Index of this node | 
|---|
| 143 |  | 
|---|
| 144 | public: | 
|---|
| 145 | typedef enum { | 
|---|
| 146 | UnknownType = 0, | 
|---|
| 147 | JavaObject  = 1, | 
|---|
| 148 | LocalVar    = 2, | 
|---|
| 149 | Field       = 3, | 
|---|
| 150 | Arraycopy   = 4 | 
|---|
| 151 | } NodeType; | 
|---|
| 152 |  | 
|---|
| 153 | typedef enum { | 
|---|
| 154 | UnknownEscape = 0, | 
|---|
| 155 | NoEscape      = 1, // An object does not escape method or thread and it is | 
|---|
| 156 | // not passed to call. It could be replaced with scalar. | 
|---|
| 157 | ArgEscape     = 2, // An object does not escape method or thread but it is | 
|---|
| 158 | // passed as argument to call or referenced by argument | 
|---|
| 159 | // and it does not escape during call. | 
|---|
| 160 | GlobalEscape  = 3  // An object escapes the method or thread. | 
|---|
| 161 | } EscapeState; | 
|---|
| 162 |  | 
|---|
| 163 | typedef enum { | 
|---|
| 164 | ScalarReplaceable = 1,  // Not escaped object could be replaced with scalar | 
|---|
| 165 | PointsToUnknown   = 2,  // Has edge to phantom_object | 
|---|
| 166 | ArraycopySrc      = 4,  // Has edge from Arraycopy node | 
|---|
| 167 | ArraycopyDst      = 8   // Has edge to Arraycopy node | 
|---|
| 168 | } NodeFlags; | 
|---|
| 169 |  | 
|---|
| 170 |  | 
|---|
| 171 | inline PointsToNode(ConnectionGraph* CG, Node* n, EscapeState es, NodeType type); | 
|---|
| 172 |  | 
|---|
| 173 | uint        pidx()   const { return _pidx; } | 
|---|
| 174 |  | 
|---|
| 175 | Node* ideal_node()   const { return _node; } | 
|---|
| 176 | int          idx()   const { return _idx; } | 
|---|
| 177 |  | 
|---|
| 178 | bool is_JavaObject() const { return _type == (u1)JavaObject; } | 
|---|
| 179 | bool is_LocalVar()   const { return _type == (u1)LocalVar; } | 
|---|
| 180 | bool is_Field()      const { return _type == (u1)Field; } | 
|---|
| 181 | bool is_Arraycopy()  const { return _type == (u1)Arraycopy; } | 
|---|
| 182 |  | 
|---|
| 183 | JavaObjectNode* as_JavaObject() { assert(is_JavaObject(), ""); return (JavaObjectNode*)this; } | 
|---|
| 184 | LocalVarNode*   as_LocalVar()   { assert(is_LocalVar(), "");   return (LocalVarNode*)this; } | 
|---|
| 185 | FieldNode*      as_Field()      { assert(is_Field(), "");      return (FieldNode*)this; } | 
|---|
| 186 | ArraycopyNode*  as_Arraycopy()  { assert(is_Arraycopy(), "");  return (ArraycopyNode*)this; } | 
|---|
| 187 |  | 
|---|
| 188 | EscapeState escape_state() const { return (EscapeState)_escape; } | 
|---|
| 189 | void    set_escape_state(EscapeState state) { _escape = (u1)state; } | 
|---|
| 190 |  | 
|---|
| 191 | EscapeState fields_escape_state() const { return (EscapeState)_fields_escape; } | 
|---|
| 192 | void    set_fields_escape_state(EscapeState state) { _fields_escape = (u1)state; } | 
|---|
| 193 |  | 
|---|
| 194 | bool     has_unknown_ptr() const { return (_flags & PointsToUnknown) != 0; } | 
|---|
| 195 | void set_has_unknown_ptr()       { _flags |= PointsToUnknown; } | 
|---|
| 196 |  | 
|---|
| 197 | bool     arraycopy_src() const { return (_flags & ArraycopySrc) != 0; } | 
|---|
| 198 | void set_arraycopy_src()       { _flags |= ArraycopySrc; } | 
|---|
| 199 | bool     arraycopy_dst() const { return (_flags & ArraycopyDst) != 0; } | 
|---|
| 200 | void set_arraycopy_dst()       { _flags |= ArraycopyDst; } | 
|---|
| 201 |  | 
|---|
| 202 | bool     scalar_replaceable() const { return (_flags & ScalarReplaceable) != 0;} | 
|---|
| 203 | void set_scalar_replaceable(bool v) { | 
|---|
| 204 | if (v) | 
|---|
| 205 | _flags |= ScalarReplaceable; | 
|---|
| 206 | else | 
|---|
| 207 | _flags &= ~ScalarReplaceable; | 
|---|
| 208 | } | 
|---|
| 209 |  | 
|---|
| 210 | int edge_count()              const { return _edges.length(); } | 
|---|
| 211 | PointsToNode* edge(int e)     const { return _edges.at(e); } | 
|---|
| 212 | bool add_edge(PointsToNode* edge)    { return _edges.append_if_missing(edge); } | 
|---|
| 213 |  | 
|---|
| 214 | int use_count()             const { return _uses.length(); } | 
|---|
| 215 | PointsToNode* use(int e)    const { return _uses.at(e); } | 
|---|
| 216 | bool add_use(PointsToNode* use)    { return _uses.append_if_missing(use); } | 
|---|
| 217 |  | 
|---|
| 218 | // Mark base edge use to distinguish from stored value edge. | 
|---|
| 219 | bool add_base_use(FieldNode* use) { return _uses.append_if_missing((PointsToNode*)((intptr_t)use + 1)); } | 
|---|
| 220 | static bool is_base_use(PointsToNode* use) { return (((intptr_t)use) & 1); } | 
|---|
| 221 | static PointsToNode* get_use_node(PointsToNode* use) { return (PointsToNode*)(((intptr_t)use) & ~1); } | 
|---|
| 222 |  | 
|---|
| 223 | // Return true if this node points to specified node or nodes it points to. | 
|---|
| 224 | bool points_to(JavaObjectNode* ptn) const; | 
|---|
| 225 |  | 
|---|
| 226 | // Return true if this node points only to non-escaping allocations. | 
|---|
| 227 | bool non_escaping_allocation(); | 
|---|
| 228 |  | 
|---|
| 229 | // Return true if one node points to an other. | 
|---|
| 230 | bool meet(PointsToNode* ptn); | 
|---|
| 231 |  | 
|---|
| 232 | #ifndef PRODUCT | 
|---|
| 233 | NodeType node_type() const { return (NodeType)_type;} | 
|---|
| 234 | void dump(bool print_state=true) const; | 
|---|
| 235 | #endif | 
|---|
| 236 |  | 
|---|
| 237 | }; | 
|---|
| 238 |  | 
|---|
| 239 | class LocalVarNode: public PointsToNode { | 
|---|
| 240 | public: | 
|---|
| 241 | LocalVarNode(ConnectionGraph *CG, Node* n, EscapeState es): | 
|---|
| 242 | PointsToNode(CG, n, es, LocalVar) {} | 
|---|
| 243 | }; | 
|---|
| 244 |  | 
|---|
| 245 | class JavaObjectNode: public PointsToNode { | 
|---|
| 246 | public: | 
|---|
| 247 | JavaObjectNode(ConnectionGraph *CG, Node* n, EscapeState es): | 
|---|
| 248 | PointsToNode(CG, n, es, JavaObject) { | 
|---|
| 249 | if (es > NoEscape) | 
|---|
| 250 | set_scalar_replaceable(false); | 
|---|
| 251 | } | 
|---|
| 252 | }; | 
|---|
| 253 |  | 
|---|
| 254 | class FieldNode: public PointsToNode { | 
|---|
| 255 | GrowableArray<PointsToNode*> _bases; // List of JavaObject nodes which point to this node | 
|---|
| 256 | const int   _offset; // Field's offset. | 
|---|
| 257 | const bool  _is_oop; // Field points to object | 
|---|
| 258 | bool  _has_unknown_base; // Has phantom_object base | 
|---|
| 259 | public: | 
|---|
| 260 | FieldNode(ConnectionGraph *CG, Node* n, EscapeState es, int offs, bool is_oop): | 
|---|
| 261 | PointsToNode(CG, n, es, Field), | 
|---|
| 262 | _offset(offs), _is_oop(is_oop), | 
|---|
| 263 | _has_unknown_base(false) {} | 
|---|
| 264 |  | 
|---|
| 265 | int      offset()              const { return _offset;} | 
|---|
| 266 | bool     is_oop()              const { return _is_oop;} | 
|---|
| 267 | bool     has_unknown_base()    const { return _has_unknown_base; } | 
|---|
| 268 | void set_has_unknown_base()          { _has_unknown_base = true; } | 
|---|
| 269 |  | 
|---|
| 270 | int base_count()              const { return _bases.length(); } | 
|---|
| 271 | PointsToNode* base(int e)     const { return _bases.at(e); } | 
|---|
| 272 | bool add_base(PointsToNode* base)    { return _bases.append_if_missing(base); } | 
|---|
| 273 | #ifdef ASSERT | 
|---|
| 274 | // Return true if bases points to this java object. | 
|---|
| 275 | bool has_base(JavaObjectNode* ptn) const; | 
|---|
| 276 | #endif | 
|---|
| 277 |  | 
|---|
| 278 | }; | 
|---|
| 279 |  | 
|---|
| 280 | class ArraycopyNode: public PointsToNode { | 
|---|
| 281 | public: | 
|---|
| 282 | ArraycopyNode(ConnectionGraph *CG, Node* n, EscapeState es): | 
|---|
| 283 | PointsToNode(CG, n, es, Arraycopy) {} | 
|---|
| 284 | }; | 
|---|
| 285 |  | 
|---|
| 286 | // Iterators for PointsTo node's edges: | 
|---|
| 287 | //   for (EdgeIterator i(n); i.has_next(); i.next()) { | 
|---|
| 288 | //     PointsToNode* u = i.get(); | 
|---|
| 289 | class PointsToIterator: public StackObj { | 
|---|
| 290 | protected: | 
|---|
| 291 | const PointsToNode* node; | 
|---|
| 292 | const int cnt; | 
|---|
| 293 | int i; | 
|---|
| 294 | public: | 
|---|
| 295 | inline PointsToIterator(const PointsToNode* n, int cnt) : node(n), cnt(cnt), i(0) { } | 
|---|
| 296 | inline bool has_next() const { return i < cnt; } | 
|---|
| 297 | inline void next() { i++; } | 
|---|
| 298 | PointsToNode* get() const { ShouldNotCallThis(); return NULL; } | 
|---|
| 299 | }; | 
|---|
| 300 |  | 
|---|
| 301 | class EdgeIterator: public PointsToIterator { | 
|---|
| 302 | public: | 
|---|
| 303 | inline EdgeIterator(const PointsToNode* n) : PointsToIterator(n, n->edge_count()) { } | 
|---|
| 304 | inline PointsToNode* get() const { return node->edge(i); } | 
|---|
| 305 | }; | 
|---|
| 306 |  | 
|---|
| 307 | class UseIterator: public PointsToIterator { | 
|---|
| 308 | public: | 
|---|
| 309 | inline UseIterator(const PointsToNode* n) : PointsToIterator(n, n->use_count()) { } | 
|---|
| 310 | inline PointsToNode* get() const { return node->use(i); } | 
|---|
| 311 | }; | 
|---|
| 312 |  | 
|---|
| 313 | class BaseIterator: public PointsToIterator { | 
|---|
| 314 | public: | 
|---|
| 315 | inline BaseIterator(const FieldNode* n) : PointsToIterator(n, n->base_count()) { } | 
|---|
| 316 | inline PointsToNode* get() const { return ((PointsToNode*)node)->as_Field()->base(i); } | 
|---|
| 317 | }; | 
|---|
| 318 |  | 
|---|
| 319 |  | 
|---|
| 320 | class ConnectionGraph: public ResourceObj { | 
|---|
| 321 | friend class PointsToNode; | 
|---|
| 322 | private: | 
|---|
| 323 | GrowableArray<PointsToNode*>  _nodes; // Map from ideal nodes to | 
|---|
| 324 | // ConnectionGraph nodes. | 
|---|
| 325 |  | 
|---|
| 326 | GrowableArray<PointsToNode*>  _worklist; // Nodes to be processed | 
|---|
| 327 | VectorSet                  _in_worklist; | 
|---|
| 328 | uint                         _next_pidx; | 
|---|
| 329 |  | 
|---|
| 330 | bool            _collecting; // Indicates whether escape information | 
|---|
| 331 | // is still being collected. If false, | 
|---|
| 332 | // no new nodes will be processed. | 
|---|
| 333 |  | 
|---|
| 334 | bool               _verify;  // verify graph | 
|---|
| 335 |  | 
|---|
| 336 | JavaObjectNode* phantom_obj; // Unknown object | 
|---|
| 337 | JavaObjectNode*    null_obj; | 
|---|
| 338 | Node*             _pcmp_neq; // ConI(#CC_GT) | 
|---|
| 339 | Node*              _pcmp_eq; // ConI(#CC_EQ) | 
|---|
| 340 |  | 
|---|
| 341 | Compile*           _compile; // Compile object for current compilation | 
|---|
| 342 | PhaseIterGVN*         _igvn; // Value numbering | 
|---|
| 343 |  | 
|---|
| 344 | Unique_Node_List ideal_nodes; // Used by CG construction and types splitting. | 
|---|
| 345 |  | 
|---|
| 346 | // Address of an element in _nodes.  Used when the element is to be modified | 
|---|
| 347 | PointsToNode* ptnode_adr(int idx) const { | 
|---|
| 348 | // There should be no new ideal nodes during ConnectionGraph build, | 
|---|
| 349 | // growableArray::at() will throw assert otherwise. | 
|---|
| 350 | return _nodes.at(idx); | 
|---|
| 351 | } | 
|---|
| 352 | uint nodes_size() const { return _nodes.length(); } | 
|---|
| 353 |  | 
|---|
| 354 | uint next_pidx() { return _next_pidx++; } | 
|---|
| 355 |  | 
|---|
| 356 | // Add nodes to ConnectionGraph. | 
|---|
| 357 | void add_local_var(Node* n, PointsToNode::EscapeState es); | 
|---|
| 358 | void add_java_object(Node* n, PointsToNode::EscapeState es); | 
|---|
| 359 | void add_field(Node* n, PointsToNode::EscapeState es, int offset); | 
|---|
| 360 | void add_arraycopy(Node* n, PointsToNode::EscapeState es, PointsToNode* src, PointsToNode* dst); | 
|---|
| 361 |  | 
|---|
| 362 | // Compute the escape state for arguments to a call. | 
|---|
| 363 | void process_call_arguments(CallNode *call); | 
|---|
| 364 |  | 
|---|
| 365 | // Add PointsToNode node corresponding to a call | 
|---|
| 366 | void add_call_node(CallNode* call); | 
|---|
| 367 |  | 
|---|
| 368 | // Map ideal node to existing PointsTo node (usually phantom_object). | 
|---|
| 369 | void map_ideal_node(Node *n, PointsToNode* ptn) { | 
|---|
| 370 | assert(ptn != NULL, "only existing PointsTo node"); | 
|---|
| 371 | _nodes.at_put(n->_idx, ptn); | 
|---|
| 372 | } | 
|---|
| 373 |  | 
|---|
| 374 | // Create PointsToNode node and add it to Connection Graph. | 
|---|
| 375 | void add_node_to_connection_graph(Node *n, Unique_Node_List *delayed_worklist); | 
|---|
| 376 |  | 
|---|
| 377 | // Add final simple edges to graph. | 
|---|
| 378 | void add_final_edges(Node *n); | 
|---|
| 379 |  | 
|---|
| 380 | // Finish Graph construction. | 
|---|
| 381 | bool complete_connection_graph(GrowableArray<PointsToNode*>&   ptnodes_worklist, | 
|---|
| 382 | GrowableArray<JavaObjectNode*>& non_escaped_worklist, | 
|---|
| 383 | GrowableArray<JavaObjectNode*>& java_objects_worklist, | 
|---|
| 384 | GrowableArray<FieldNode*>&      oop_fields_worklist); | 
|---|
| 385 |  | 
|---|
| 386 | #ifdef ASSERT | 
|---|
| 387 | void verify_connection_graph(GrowableArray<PointsToNode*>&   ptnodes_worklist, | 
|---|
| 388 | GrowableArray<JavaObjectNode*>& non_escaped_worklist, | 
|---|
| 389 | GrowableArray<JavaObjectNode*>& java_objects_worklist, | 
|---|
| 390 | GrowableArray<Node*>& addp_worklist); | 
|---|
| 391 | #endif | 
|---|
| 392 |  | 
|---|
| 393 | // Add all references to this JavaObject node. | 
|---|
| 394 | int add_java_object_edges(JavaObjectNode* jobj, bool populate_worklist); | 
|---|
| 395 |  | 
|---|
| 396 | // Put node on worklist if it is (or was) not there. | 
|---|
| 397 | inline void add_to_worklist(PointsToNode* pt) { | 
|---|
| 398 | PointsToNode* ptf = pt; | 
|---|
| 399 | uint pidx_bias = 0; | 
|---|
| 400 | if (PointsToNode::is_base_use(pt)) { | 
|---|
| 401 | // Create a separate entry in _in_worklist for a marked base edge | 
|---|
| 402 | // because _worklist may have an entry for a normal edge pointing | 
|---|
| 403 | // to the same node. To separate them use _next_pidx as bias. | 
|---|
| 404 | ptf = PointsToNode::get_use_node(pt)->as_Field(); | 
|---|
| 405 | pidx_bias = _next_pidx; | 
|---|
| 406 | } | 
|---|
| 407 | if (!_in_worklist.test_set(ptf->pidx() + pidx_bias)) { | 
|---|
| 408 | _worklist.append(pt); | 
|---|
| 409 | } | 
|---|
| 410 | } | 
|---|
| 411 |  | 
|---|
| 412 | // Put on worklist all uses of this node. | 
|---|
| 413 | inline void add_uses_to_worklist(PointsToNode* pt) { | 
|---|
| 414 | for (UseIterator i(pt); i.has_next(); i.next()) { | 
|---|
| 415 | add_to_worklist(i.get()); | 
|---|
| 416 | } | 
|---|
| 417 | } | 
|---|
| 418 |  | 
|---|
| 419 | // Put on worklist all field's uses and related field nodes. | 
|---|
| 420 | void add_field_uses_to_worklist(FieldNode* field); | 
|---|
| 421 |  | 
|---|
| 422 | // Put on worklist all related field nodes. | 
|---|
| 423 | void add_fields_to_worklist(FieldNode* field, PointsToNode* base); | 
|---|
| 424 |  | 
|---|
| 425 | // Find fields which have unknown value. | 
|---|
| 426 | int find_field_value(FieldNode* field); | 
|---|
| 427 |  | 
|---|
| 428 | // Find fields initializing values for allocations. | 
|---|
| 429 | int find_init_values(JavaObjectNode* ptn, PointsToNode* init_val, PhaseTransform* phase); | 
|---|
| 430 |  | 
|---|
| 431 | // Set the escape state of an object and its fields. | 
|---|
| 432 | void set_escape_state(PointsToNode* ptn, PointsToNode::EscapeState esc) { | 
|---|
| 433 | // Don't change non-escaping state of NULL pointer. | 
|---|
| 434 | if (ptn != null_obj) { | 
|---|
| 435 | if (ptn->escape_state() < esc) | 
|---|
| 436 | ptn->set_escape_state(esc); | 
|---|
| 437 | if (ptn->fields_escape_state() < esc) | 
|---|
| 438 | ptn->set_fields_escape_state(esc); | 
|---|
| 439 | } | 
|---|
| 440 | } | 
|---|
| 441 | void set_fields_escape_state(PointsToNode* ptn, PointsToNode::EscapeState esc) { | 
|---|
| 442 | // Don't change non-escaping state of NULL pointer. | 
|---|
| 443 | if (ptn != null_obj) { | 
|---|
| 444 | if (ptn->fields_escape_state() < esc) | 
|---|
| 445 | ptn->set_fields_escape_state(esc); | 
|---|
| 446 | } | 
|---|
| 447 | } | 
|---|
| 448 |  | 
|---|
| 449 | // Propagate GlobalEscape and ArgEscape escape states to all nodes | 
|---|
| 450 | // and check that we still have non-escaping java objects. | 
|---|
| 451 | bool find_non_escaped_objects(GrowableArray<PointsToNode*>& ptnodes_worklist, | 
|---|
| 452 | GrowableArray<JavaObjectNode*>& non_escaped_worklist); | 
|---|
| 453 |  | 
|---|
| 454 | // Adjust scalar_replaceable state after Connection Graph is built. | 
|---|
| 455 | void adjust_scalar_replaceable_state(JavaObjectNode* jobj); | 
|---|
| 456 |  | 
|---|
| 457 | // Optimize ideal graph. | 
|---|
| 458 | void optimize_ideal_graph(GrowableArray<Node*>& ptr_cmp_worklist, | 
|---|
| 459 | GrowableArray<Node*>& storestore_worklist); | 
|---|
| 460 | // Optimize objects compare. | 
|---|
| 461 | Node* optimize_ptr_compare(Node* n); | 
|---|
| 462 |  | 
|---|
| 463 | // Returns unique corresponding java object or NULL. | 
|---|
| 464 | JavaObjectNode* unique_java_object(Node *n); | 
|---|
| 465 |  | 
|---|
| 466 | // Add an edge of the specified type pointing to the specified target. | 
|---|
| 467 | bool add_edge(PointsToNode* from, PointsToNode* to) { | 
|---|
| 468 | assert(!from->is_Field() || from->as_Field()->is_oop(), "sanity"); | 
|---|
| 469 |  | 
|---|
| 470 | if (to == phantom_obj) { | 
|---|
| 471 | if (from->has_unknown_ptr()) { | 
|---|
| 472 | return false; // already points to phantom_obj | 
|---|
| 473 | } | 
|---|
| 474 | from->set_has_unknown_ptr(); | 
|---|
| 475 | } | 
|---|
| 476 |  | 
|---|
| 477 | bool is_new = from->add_edge(to); | 
|---|
| 478 | assert(to != phantom_obj || is_new, "sanity"); | 
|---|
| 479 | if (is_new) { // New edge? | 
|---|
| 480 | assert(!_verify, "graph is incomplete"); | 
|---|
| 481 | is_new = to->add_use(from); | 
|---|
| 482 | assert(is_new, "use should be also new"); | 
|---|
| 483 | } | 
|---|
| 484 | return is_new; | 
|---|
| 485 | } | 
|---|
| 486 |  | 
|---|
| 487 | // Add an edge from Field node to its base and back. | 
|---|
| 488 | bool add_base(FieldNode* from, PointsToNode* to) { | 
|---|
| 489 | assert(!to->is_Arraycopy(), "sanity"); | 
|---|
| 490 | if (to == phantom_obj) { | 
|---|
| 491 | if (from->has_unknown_base()) { | 
|---|
| 492 | return false; // already has phantom_obj base | 
|---|
| 493 | } | 
|---|
| 494 | from->set_has_unknown_base(); | 
|---|
| 495 | } | 
|---|
| 496 | bool is_new = from->add_base(to); | 
|---|
| 497 | assert(to != phantom_obj || is_new, "sanity"); | 
|---|
| 498 | if (is_new) {      // New edge? | 
|---|
| 499 | assert(!_verify, "graph is incomplete"); | 
|---|
| 500 | if (to == null_obj) | 
|---|
| 501 | return is_new; // Don't add fields to NULL pointer. | 
|---|
| 502 | if (to->is_JavaObject()) { | 
|---|
| 503 | is_new = to->add_edge(from); | 
|---|
| 504 | } else { | 
|---|
| 505 | is_new = to->add_base_use(from); | 
|---|
| 506 | } | 
|---|
| 507 | assert(is_new, "use should be also new"); | 
|---|
| 508 | } | 
|---|
| 509 | return is_new; | 
|---|
| 510 | } | 
|---|
| 511 |  | 
|---|
| 512 | // Helper functions | 
|---|
| 513 | bool   is_oop_field(Node* n, int offset, bool* unsafe); | 
|---|
| 514 | static Node* find_second_addp(Node* addp, Node* n); | 
|---|
| 515 | // offset of a field reference | 
|---|
| 516 | int address_offset(Node* adr, PhaseTransform *phase); | 
|---|
| 517 |  | 
|---|
| 518 |  | 
|---|
| 519 | // Propagate unique types created for unescaped allocated objects | 
|---|
| 520 | // through the graph | 
|---|
| 521 | void split_unique_types(GrowableArray<Node *>  &alloc_worklist, GrowableArray<ArrayCopyNode*> &arraycopy_worklist); | 
|---|
| 522 |  | 
|---|
| 523 | // Helper methods for unique types split. | 
|---|
| 524 | bool split_AddP(Node *addp, Node *base); | 
|---|
| 525 |  | 
|---|
| 526 | PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *>  &orig_phi_worklist, bool &new_created); | 
|---|
| 527 | PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *>  &orig_phi_worklist); | 
|---|
| 528 |  | 
|---|
| 529 | void  move_inst_mem(Node* n, GrowableArray<PhiNode *>  &orig_phis); | 
|---|
| 530 | Node* find_inst_mem(Node* mem, int alias_idx,GrowableArray<PhiNode *>  &orig_phi_worklist); | 
|---|
| 531 | Node* step_through_mergemem(MergeMemNode *mmem, int alias_idx, const TypeOopPtr *toop); | 
|---|
| 532 |  | 
|---|
| 533 |  | 
|---|
| 534 | GrowableArray<MergeMemNode*>  _mergemem_worklist; // List of all MergeMem nodes | 
|---|
| 535 |  | 
|---|
| 536 | Node_Array _node_map; // used for bookeeping during type splitting | 
|---|
| 537 | // Used for the following purposes: | 
|---|
| 538 | // Memory Phi    - most recent unique Phi split out | 
|---|
| 539 | //                 from this Phi | 
|---|
| 540 | // MemNode       - new memory input for this node | 
|---|
| 541 | // ChecCastPP    - allocation that this is a cast of | 
|---|
| 542 | // allocation    - CheckCastPP of the allocation | 
|---|
| 543 |  | 
|---|
| 544 | // manage entries in _node_map | 
|---|
| 545 |  | 
|---|
| 546 | void  set_map(Node* from, Node* to)  { | 
|---|
| 547 | ideal_nodes.push(from); | 
|---|
| 548 | _node_map.map(from->_idx, to); | 
|---|
| 549 | } | 
|---|
| 550 |  | 
|---|
| 551 | Node* get_map(int idx) { return _node_map[idx]; } | 
|---|
| 552 |  | 
|---|
| 553 | PhiNode* get_map_phi(int idx) { | 
|---|
| 554 | Node* phi = _node_map[idx]; | 
|---|
| 555 | return (phi == NULL) ? NULL : phi->as_Phi(); | 
|---|
| 556 | } | 
|---|
| 557 |  | 
|---|
| 558 | // Notify optimizer that a node has been modified | 
|---|
| 559 | void record_for_optimizer(Node *n); | 
|---|
| 560 |  | 
|---|
| 561 | // Compute the escape information | 
|---|
| 562 | bool compute_escape(); | 
|---|
| 563 |  | 
|---|
| 564 | public: | 
|---|
| 565 | ConnectionGraph(Compile *C, PhaseIterGVN *igvn); | 
|---|
| 566 |  | 
|---|
| 567 | // Check for non-escaping candidates | 
|---|
| 568 | static bool has_candidates(Compile *C); | 
|---|
| 569 |  | 
|---|
| 570 | // Perform escape analysis | 
|---|
| 571 | static void do_analysis(Compile *C, PhaseIterGVN *igvn); | 
|---|
| 572 |  | 
|---|
| 573 | bool not_global_escape(Node *n); | 
|---|
| 574 |  | 
|---|
| 575 | // To be used by, e.g., BarrierSetC2 impls | 
|---|
| 576 | Node* get_addp_base(Node* addp); | 
|---|
| 577 |  | 
|---|
| 578 | // Utility function for nodes that load an object | 
|---|
| 579 | void add_objload_to_connection_graph(Node* n, Unique_Node_List* delayed_worklist); | 
|---|
| 580 |  | 
|---|
| 581 | // Add LocalVar node and edge if possible | 
|---|
| 582 | void add_local_var_and_edge(Node* n, PointsToNode::EscapeState es, Node* to, | 
|---|
| 583 | Unique_Node_List *delayed_worklist) { | 
|---|
| 584 | PointsToNode* ptn = ptnode_adr(to->_idx); | 
|---|
| 585 | if (delayed_worklist != NULL) { // First iteration of CG construction | 
|---|
| 586 | add_local_var(n, es); | 
|---|
| 587 | if (ptn == NULL) { | 
|---|
| 588 | delayed_worklist->push(n); | 
|---|
| 589 | return; // Process it later. | 
|---|
| 590 | } | 
|---|
| 591 | } else { | 
|---|
| 592 | assert(ptn != NULL, "node should be registered"); | 
|---|
| 593 | } | 
|---|
| 594 | add_edge(ptnode_adr(n->_idx), ptn); | 
|---|
| 595 | } | 
|---|
| 596 |  | 
|---|
| 597 | void add_to_congraph_unsafe_access(Node* n, uint opcode, Unique_Node_List* delayed_worklist); | 
|---|
| 598 | bool add_final_edges_unsafe_access(Node* n, uint opcode); | 
|---|
| 599 |  | 
|---|
| 600 | #ifndef PRODUCT | 
|---|
| 601 | void dump(GrowableArray<PointsToNode*>& ptnodes_worklist); | 
|---|
| 602 | #endif | 
|---|
| 603 | }; | 
|---|
| 604 |  | 
|---|
| 605 | inline PointsToNode::PointsToNode(ConnectionGraph *CG, Node* n, EscapeState es, NodeType type): | 
|---|
| 606 | _edges(CG->_compile->comp_arena(), 2, 0, NULL), | 
|---|
| 607 | _uses (CG->_compile->comp_arena(), 2, 0, NULL), | 
|---|
| 608 | _type((u1)type), | 
|---|
| 609 | _flags(ScalarReplaceable), | 
|---|
| 610 | _escape((u1)es), | 
|---|
| 611 | _fields_escape((u1)es), | 
|---|
| 612 | _node(n), | 
|---|
| 613 | _idx(n->_idx), | 
|---|
| 614 | _pidx(CG->next_pidx()) { | 
|---|
| 615 | assert(n != NULL && es != UnknownEscape, "sanity"); | 
|---|
| 616 | } | 
|---|
| 617 |  | 
|---|
| 618 | #endif // SHARE_OPTO_ESCAPE_HPP | 
|---|
| 619 |  | 
|---|