1 /* 2 * Copyright Amazon.com Inc. 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_PARTIAL_ESCAPE_HPP 26 #define SHARE_OPTO_PARTIAL_ESCAPE_HPP 27 28 #include "opto/type.hpp" 29 #include "utilities/resourceHash.hpp" 30 31 // forward declaration 32 class GraphKit; 33 34 class ObjectState { 35 friend class PEAState; 36 37 // ObjectState(const ObjectState&) = delete; 38 protected: 39 int _refcnt = 0; 40 void ref_inc() { _refcnt++; } 41 int ref_dec() { return --_refcnt; } 42 int ref_cnt(int cnt) { 43 int old = _refcnt; 44 _refcnt = cnt; 45 return old; 46 } 47 48 public: 49 inline void* operator new(size_t x) throw() { 50 Compile* C = Compile::current(); 51 return C->parser_arena()->AmallocWords(x); 52 } 53 54 virtual bool is_virtual() const = 0; 55 // clone contents but not refcnt; 56 virtual ObjectState* clone() const = 0; 57 58 int ref_cnt() const { return _refcnt; } 59 60 virtual ObjectState& merge(ObjectState* newin, GraphKit* kit, RegionNode* region, int pnum) = 0; 61 }; 62 63 class VirtualState: public ObjectState { 64 friend class PEAState; 65 const TypeOopPtr* const _oop_type; 66 int _lockcnt; 67 Node** _entries; 68 69 protected: 70 VirtualState(const VirtualState& other); 71 72 public: 73 VirtualState(const TypeOopPtr* oop_type); 74 75 bool is_virtual() const override { return true; } 76 77 ObjectState* clone() const override { 78 return new VirtualState(*this); 79 } 80 81 int nfields() const; 82 void set_field(ciField* field, Node* val); 83 Node* get_field(ciField* field) const; 84 85 ObjectState& merge(ObjectState* newin, GraphKit* kit, RegionNode* region, int pnum) override; 86 87 void lock_inc() { _lockcnt++; } 88 void lock_dec() { 89 assert(_lockcnt > 0, "sanity check"); 90 --_lockcnt; 91 } 92 int lockcnt() const { 93 return _lockcnt; 94 } 95 96 #ifndef PRODUCT 97 void print_on(outputStream* os) const; 98 #endif 99 100 class iterator { 101 private: 102 const VirtualState* _state; 103 int _end; 104 int _idx; 105 106 public: 107 iterator(const VirtualState* state): _state(state), _idx(0) { 108 const TypeInstPtr* instptr = _state->_oop_type->isa_instptr(); 109 if (instptr != nullptr) { 110 ciInstanceKlass* holder = instptr->instance_klass(); 111 _end = holder->nof_nonstatic_fields(); 112 } else { 113 _end = 0; 114 } 115 } 116 117 bool has_next() const { 118 return _idx < _end; 119 } 120 121 void operator++() { 122 assert(has_next(), "out of range."); 123 ++_idx; 124 } 125 126 ciField* field() const { 127 assert(_idx < _end, "sanity"); 128 ciInstanceKlass* ik = _state->_oop_type->is_instptr()->instance_klass(); 129 return ik->nonstatic_field_at(_idx); 130 } 131 132 Node* value() const { 133 assert(_idx < _end, "sanity check"); 134 assert(_idx >= 0 && _idx < _state->nfields(), "field is out of range"); 135 136 return _state->_entries[_idx]; 137 } 138 }; 139 140 iterator field_iterator() { 141 return {this}; 142 } 143 }; 144 145 class EscapedState: public ObjectState { 146 bool _materialized; // we may skip passive materialization. 147 Node* _merged_value; // the latest java_oop 148 149 public: 150 EscapedState(bool materialized, Node* value) : _materialized(materialized), _merged_value(value) {} 151 152 bool is_virtual() const override { return false;} 153 154 Node* materialized_value() const { 155 return _materialized ? _merged_value : nullptr; 156 } 157 158 Node* merged_value() const { 159 return _merged_value; 160 } 161 162 bool has_materialized() const { 163 return _materialized; 164 } 165 166 void update(bool materialized, Node* node) { 167 assert(node != nullptr, "assign a nullptr as merged value"); 168 assert(materialized || !_materialized, "reverting _materialized is wrong"); 169 170 _materialized = materialized; 171 _merged_value = node; 172 } 173 174 void update(Node* node) { 175 update(_materialized, node); 176 } 177 178 ObjectState* clone() const override { 179 return new EscapedState(_materialized, _merged_value); 180 } 181 182 ObjectState& merge(ObjectState* newin, GraphKit* kit, RegionNode* region, int pnum) override { 183 assert(0, "not implemented"); 184 return *this; 185 } 186 187 #ifndef PRODUCT 188 void print_on(outputStream* os) const; 189 #endif 190 }; 191 192 template<typename K, typename V> 193 using PEAMap = ResourceHashtable<K, V, 17, /*table_size*/ 194 AnyObj::C_HEAP, mtCompiler>; 195 196 class PartialEscapeAnalysis : public AnyObj { 197 // alias maps from node to ObjID. 198 PEAMap<Node*, ObjID> _aliases; 199 GrowableArray<ObjID> _objects; 200 201 public: 202 PartialEscapeAnalysis(Arena* arena): _aliases(), _objects(arena, 2, 0, nullptr) {} 203 204 ObjID is_alias(Node* node) const { 205 assert(node != nullptr || !_aliases.contains(node), "_aliases.contain(nullptr) must return false"); 206 if (_aliases.contains(node)) { 207 return *(_aliases.get(node)); 208 } else { 209 return nullptr; 210 } 211 } 212 213 // refcount is the no. of aliases which refer to the object. 214 // we do garbage collection if refcnt drops to 0. 215 void add_alias(ObjID id, Node* var) { 216 assert(!_aliases.contains(var) || (*_aliases.get(var)) == id, "redefine an alias to another object"); 217 if (_aliases.contains(var)) return; 218 _aliases.put(var, id); 219 } 220 221 void remove_alias(ObjID id, Node* var) { 222 assert(_aliases.contains(var) && (*_aliases.get(var)) == id, "sanity check"); 223 _aliases.remove(var); 224 } 225 226 // PEA tracks all new instances in the current compilation unit 227 // so we could bisect for bugs. 228 int add_object(ObjID obj) { 229 _objects.push(obj); 230 return _objects.length() - 1; 231 } 232 233 int object_idx(ObjID obj) const { 234 return _objects.find(obj); 235 } 236 237 const GrowableArray<ObjID>& all_objects() const { 238 return _objects; 239 } 240 }; 241 242 //TODO: rename it to allocation state. 243 class PEAState { 244 friend class Parse; 245 PEAMap<ObjID, ObjectState*> _state; 246 247 public: 248 PEAState& operator=(const PEAState& init); 249 250 ObjectState* get_object_state(ObjID id) const { 251 assert(contains(id), "object doesn't exist in allocation state"); 252 return *(_state.get(id)); 253 } 254 255 bool contains(ObjID id) const { 256 #ifdef ASSERT 257 if (id == nullptr) { 258 assert(!_state.contains(id), "PEAState must exclude nullptr"); 259 } 260 #endif 261 return _state.contains(id); 262 } 263 264 Node* get_materialized_value(ObjID id) const; 265 266 Node* get_java_oop(ObjID id) const; 267 268 // Convert the state of obj#id to Escaped. 269 // p is the new alias of obj#id. If materialized is true, the materiazation has taken place in code. 270 // PEA expects to replace all appearances of the object with its java_oop, or materilzied_value(). 271 // refer to GraphKit::backfill_materialized. 272 EscapedState* escape(ObjID id, Node* p, bool materialized); 273 274 void add_new_allocation(GraphKit* kit, Node* obj); 275 276 Node* materialize(GraphKit* kit, Node* var); 277 278 void put_field(GraphKit* kit, ciField* field, Node* objx, Node* val); 279 280 int objects(Unique_Node_List& nodes) const; 281 int size() const { 282 return _state.number_of_entries(); 283 } 284 285 VirtualState* as_virtual(const PartialEscapeAnalysis* pea, Node* var) const { 286 ObjID id = pea->is_alias(var); 287 if (id != nullptr && contains(id)) { 288 ObjectState* os = get_object_state(id); 289 290 if (os->is_virtual()) { 291 return static_cast<VirtualState*>(os); 292 } 293 } 294 return nullptr; 295 } 296 297 EscapedState* as_escaped(const PartialEscapeAnalysis* pea, Node* var) const { 298 ObjID id = pea->is_alias(var); 299 if (id != nullptr && contains(id)) { 300 ObjectState* os = get_object_state(id); 301 302 if (!os->is_virtual()) { 303 return static_cast<EscapedState*>(os); 304 } 305 } 306 return nullptr; 307 } 308 309 void clear() { 310 _state.unlink_all(); 311 } 312 313 // we drop out all virtual objects when we encounter a loop header. 314 void mark_all_escaped(PartialEscapeAnalysis* pea, ObjID id, Node *obj); 315 void mark_all_live_objects_escaped(PartialEscapeAnalysis *pea, SafePointNode* map); 316 317 #ifndef PRODUCT 318 void print_on(outputStream* os) const; 319 #endif 320 321 #ifdef ASSERT 322 void validate() const; 323 #endif 324 }; 325 326 class AllocationStateMerger { 327 private: 328 GrowableArray<ObjID> _live; // live objects 329 PEAState& _state; 330 void process_phi(PhiNode* phi, GraphKit* kit, RegionNode* region, int pnum); 331 332 public: 333 AllocationStateMerger(PEAState& target); 334 ~AllocationStateMerger(); // purge all objects which are not in live. 335 void merge(PEAState& newin, GraphKit* kit, RegionNode* region, int pnum); 336 void merge_at_phi_creation(const PartialEscapeAnalysis* pea, PEAState& newin, PhiNode* phi, Node* m, Node* n); 337 }; 338 339 void printPeaStatistics(); 340 #endif // SHARE_OPTO_PARTIAL_ESCAPE_HPP