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