1 /*
2  * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.
7  *
8  * This code is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * version 2 for more details (a copy is included in the LICENSE file that
12  * accompanied this code).
13  *
14  * You should have received a copy of the GNU General Public License version
15  * 2 along with this work; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19  * or visit www.oracle.com if you need additional information or have any
20  * questions.
21  *
22  */
23 
24 #ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP
25 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP
26 
27 #include "code/codeCache.hpp"
28 #include "gc/shenandoah/shenandoahSharedVariables.hpp"
29 #include "memory/allocation.hpp"
30 #include "memory/iterator.hpp"
31 
32 class ShenandoahHeap;
33 class ShenandoahHeapRegion;
34 class ShenandoahCodeRootsLock;
35 
36 class ShenandoahParallelCodeHeapIterator {
37   friend class CodeCache;
38 private:
39   CodeHeap*     _heap;
40   DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile int));
41   volatile int  _claimed_idx;
42   volatile bool _finished;
43   DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
44 public:
45   ShenandoahParallelCodeHeapIterator(CodeHeap* heap);
46   void parallel_blobs_do(CodeBlobClosure* f);
47 };
48 
49 class ShenandoahParallelCodeCacheIterator {
50   friend class CodeCache;
51 private:
52   ShenandoahParallelCodeHeapIterator* _iters;
53   int                       _length;
54 public:
55   ShenandoahParallelCodeCacheIterator(const GrowableArray<CodeHeap*>* heaps);
56   ~ShenandoahParallelCodeCacheIterator();
57   void parallel_blobs_do(CodeBlobClosure* f);
58 };
59 
60 // ShenandoahNMethod tuple records the internal locations of oop slots within the nmethod.
61 // This allows us to quickly scan the oops without doing the nmethod-internal scans, that
62 // sometimes involves parsing the machine code. Note it does not record the oops themselves,
63 // because it would then require handling these tuples as the new class of roots.
64 class ShenandoahNMethod : public CHeapObj<mtGC> {
65 private:
66   nmethod* _nm;
67   oop**    _oops;
68   int      _oops_count;
69 
70 public:
71   ShenandoahNMethod(nmethod *nm, GrowableArray<oop*>* oops);
72   ~ShenandoahNMethod();
73 
nm()74   nmethod* nm() {
75     return _nm;
76   }
77 
78   bool has_cset_oops(ShenandoahHeap* heap);
79 
80   void assert_alive_and_correct() NOT_DEBUG_RETURN;
81   void assert_same_oops(GrowableArray<oop*>* oops) NOT_DEBUG_RETURN;
82 
find_with_nmethod(void * nm,ShenandoahNMethod * other)83   static bool find_with_nmethod(void* nm, ShenandoahNMethod* other) {
84     return other->_nm == nm;
85   }
86 };
87 
88 class ShenandoahCodeRootsIterator {
89   friend class ShenandoahCodeRoots;
90 protected:
91   ShenandoahHeap* _heap;
92   ShenandoahParallelCodeCacheIterator _par_iterator;
93   ShenandoahSharedFlag _seq_claimed;
94   DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile size_t));
95   volatile size_t _claimed;
96   DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
97 protected:
98   ShenandoahCodeRootsIterator();
99   ~ShenandoahCodeRootsIterator();
100 
101   template<bool CSET_FILTER>
102   void dispatch_parallel_blobs_do(CodeBlobClosure *f);
103 
104   template<bool CSET_FILTER>
105   void fast_parallel_blobs_do(CodeBlobClosure *f);
106 };
107 
108 class ShenandoahAllCodeRootsIterator : public ShenandoahCodeRootsIterator {
109 public:
ShenandoahAllCodeRootsIterator()110   ShenandoahAllCodeRootsIterator() : ShenandoahCodeRootsIterator() {};
111   void possibly_parallel_blobs_do(CodeBlobClosure *f);
112 };
113 
114 class ShenandoahCsetCodeRootsIterator : public ShenandoahCodeRootsIterator {
115 public:
ShenandoahCsetCodeRootsIterator()116   ShenandoahCsetCodeRootsIterator() : ShenandoahCodeRootsIterator() {};
117   void possibly_parallel_blobs_do(CodeBlobClosure* f);
118 };
119 
120 class ShenandoahCodeRoots : public CHeapObj<mtGC> {
121   friend class ShenandoahHeap;
122   friend class ShenandoahCodeRootsLock;
123   friend class ShenandoahCodeRootsIterator;
124 
125 public:
126   static void initialize();
127   static void add_nmethod(nmethod* nm);
128   static void remove_nmethod(nmethod* nm);
129 
130   /**
131    * Provides the iterator over all nmethods in the code cache that have oops.
132    * @return
133    */
134   static ShenandoahAllCodeRootsIterator iterator();
135 
136   /**
137    * Provides the iterator over nmethods that have at least one oop in collection set.
138    * @return
139    */
140   static ShenandoahCsetCodeRootsIterator cset_iterator();
141 
142 private:
143   struct PaddedLock {
144     DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile int));
145     volatile int _lock;
146     DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, 0);
147   };
148 
149   static PaddedLock _recorded_nms_lock;
150   static GrowableArray<ShenandoahNMethod*>* _recorded_nms;
151 
acquire_lock(bool write)152   static void acquire_lock(bool write) {
153     volatile int* loc = &_recorded_nms_lock._lock;
154     if (write) {
155       while ((OrderAccess::load_acquire(loc) != 0) ||
156              Atomic::cmpxchg(-1, loc, 0) != 0) {
157         SpinPause();
158       }
159       assert (*loc == -1, "acquired for write");
160     } else {
161       while (true) {
162         int cur = OrderAccess::load_acquire(loc);
163         if (cur >= 0) {
164           if (Atomic::cmpxchg(cur + 1, loc, cur) == cur) {
165             // Success!
166             assert (*loc > 0, "acquired for read");
167             return;
168           }
169         }
170         SpinPause();
171       }
172     }
173   }
174 
release_lock(bool write)175   static void release_lock(bool write) {
176     volatile int* loc = &ShenandoahCodeRoots::_recorded_nms_lock._lock;
177     if (write) {
178       OrderAccess::release_store_fence(loc, 0);
179     } else {
180       Atomic::dec(loc);
181     }
182   }
183 };
184 
185 // Very simple unranked read-write lock
186 class ShenandoahCodeRootsLock : public StackObj {
187   friend class ShenandoahCodeRoots;
188 private:
189   const bool _write;
190 public:
ShenandoahCodeRootsLock(bool write)191   ShenandoahCodeRootsLock(bool write) : _write(write) {
192     ShenandoahCodeRoots::acquire_lock(write);
193   }
194 
~ShenandoahCodeRootsLock()195   ~ShenandoahCodeRootsLock() {
196     ShenandoahCodeRoots::release_lock(_write);
197   }
198 };
199 
200 #endif //SHARE_VM_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP
201