1 /*
  2  * Copyright (c) 2018, 2020, Red Hat, Inc. 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_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP
 26 #define SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP
 27 
 28 #include "gc/shared/plab.hpp"
 29 #include "gc/shared/gcThreadLocalData.hpp"
 30 #include "gc/shared/gc_globals.hpp"
 31 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
 32 #include "gc/shenandoah/shenandoahCodeRoots.hpp"
 33 #include "gc/shenandoah/shenandoahSATBMarkQueueSet.hpp"
 34 #include "runtime/thread.hpp"
 35 #include "utilities/debug.hpp"
 36 #include "utilities/sizes.hpp"
 37 
 38 class ShenandoahThreadLocalData {
 39 public:
 40   static const uint INVALID_WORKER_ID = uint(-1);
 41 
 42 private:
 43   char _gc_state;
 44   // Evacuation OOM state
 45   uint8_t                 _oom_scope_nesting_level;
 46   bool                    _oom_during_evac;
 47   SATBMarkQueue           _satb_mark_queue;
 48 
 49   // Thread-local allocation buffer for object evacuations.
 50   // In generational mode, it is exclusive to the young generation.
 51   PLAB* _gclab;
 52   size_t _gclab_size;
 53 
 54   // Thread-local allocation buffer only used in generational mode.
 55   // Used both by mutator threads and by GC worker threads
 56   // for evacuations within the old generation and
 57   // for promotions from the young generation into the old generation.
 58   PLAB* _plab;
 59   size_t _plab_size;
 60 
 61   uint  _worker_id;
 62   int  _disarmed_value;
 63   double _paced_time;
 64 
 65   ShenandoahThreadLocalData() :
 66     _gc_state(0),
 67     _oom_scope_nesting_level(0),
 68     _oom_during_evac(false),
 69     _satb_mark_queue(&ShenandoahBarrierSet::satb_mark_queue_set()),
 70     _gclab(NULL),
 71     _gclab_size(0),
 72     _plab(NULL),
 73     _plab_size(0),
 74     _worker_id(INVALID_WORKER_ID),
 75     _disarmed_value(0),
 76     _paced_time(0) {
 77 
 78     // At least on x86_64, nmethod entry barrier encodes _disarmed_value offset
 79     // in instruction as disp8 immed
 80     assert(in_bytes(disarmed_value_offset()) < 128, "Offset range check");
 81   }
 82 
 83   ~ShenandoahThreadLocalData() {
 84     if (_gclab != NULL) {
 85       delete _gclab;
 86     }
 87     if (_plab != NULL) {
 88       delete _plab;
 89     }
 90   }
 91 
 92   static ShenandoahThreadLocalData* data(Thread* thread) {
 93     assert(UseShenandoahGC, "Sanity");
 94     return thread->gc_data<ShenandoahThreadLocalData>();
 95   }
 96 
 97   static ByteSize satb_mark_queue_offset() {
 98     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _satb_mark_queue);
 99   }
100 
101 public:
102   static void create(Thread* thread) {
103     new (data(thread)) ShenandoahThreadLocalData();
104   }
105 
106   static void destroy(Thread* thread) {
107     data(thread)->~ShenandoahThreadLocalData();
108   }
109 
110   static SATBMarkQueue& satb_mark_queue(Thread* thread) {
111     return data(thread)->_satb_mark_queue;
112   }
113 
114   static void set_gc_state(Thread* thread, char gc_state) {
115     data(thread)->_gc_state = gc_state;
116   }
117 
118   static char gc_state(Thread* thread) {
119     return data(thread)->_gc_state;
120   }
121 
122   static void set_worker_id(Thread* thread, uint id) {
123     assert(thread->is_Worker_thread(), "Must be a worker thread");
124     data(thread)->_worker_id = id;
125   }
126 
127   static uint worker_id(Thread* thread) {
128     assert(thread->is_Worker_thread(), "Must be a worker thread");
129     return data(thread)->_worker_id;
130   }
131 
132   static void initialize_gclab(Thread* thread) {
133     assert (thread->is_Java_thread() || thread->is_Worker_thread(), "Only Java and GC worker threads are allowed to get GCLABs");
134     assert(data(thread)->_gclab == NULL, "Only initialize once");
135     data(thread)->_gclab = new PLAB(PLAB::min_size());
136     data(thread)->_gclab_size = 0;
137     data(thread)->_plab = new PLAB(PLAB::min_size());
138     data(thread)->_plab_size = 0;
139   }
140 
141   static PLAB* gclab(Thread* thread) {
142     return data(thread)->_gclab;
143   }
144 
145   static size_t gclab_size(Thread* thread) {
146     return data(thread)->_gclab_size;
147   }
148 
149   static void set_gclab_size(Thread* thread, size_t v) {
150     data(thread)->_gclab_size = v;
151   }
152 
153   static PLAB* plab(Thread* thread) {
154     return data(thread)->_plab;
155   }
156 
157   static size_t plab_size(Thread* thread) {
158     return data(thread)->_plab_size;
159   }
160 
161   static void set_plab_size(Thread* thread, size_t v) {
162     data(thread)->_plab_size = v;
163   }
164 
165   static void add_paced_time(Thread* thread, double v) {
166     data(thread)->_paced_time += v;
167   }
168 
169   static double paced_time(Thread* thread) {
170     return data(thread)->_paced_time;
171   }
172 
173   static void reset_paced_time(Thread* thread) {
174     data(thread)->_paced_time = 0;
175   }
176 
177   static void set_disarmed_value(Thread* thread, int value) {
178     data(thread)->_disarmed_value = value;
179   }
180 
181   // Evacuation OOM handling
182   static bool is_oom_during_evac(Thread* thread) {
183     return data(thread)->_oom_during_evac;
184   }
185 
186   static void set_oom_during_evac(Thread* thread, bool oom) {
187     data(thread)->_oom_during_evac = oom;
188   }
189 
190   static uint8_t evac_oom_scope_level(Thread* thread) {
191     return data(thread)->_oom_scope_nesting_level;
192   }
193 
194   // Push the scope one level deeper, return previous level
195   static uint8_t push_evac_oom_scope(Thread* thread) {
196     uint8_t level = evac_oom_scope_level(thread);
197     assert(level < 254, "Overflow nesting level"); // UINT8_MAX = 255
198     data(thread)->_oom_scope_nesting_level = level + 1;
199     return level;
200   }
201 
202   // Pop the scope by one level, return previous level
203   static uint8_t pop_evac_oom_scope(Thread* thread) {
204     uint8_t level = evac_oom_scope_level(thread);
205     assert(level > 0, "Underflow nesting level");
206     data(thread)->_oom_scope_nesting_level = level - 1;
207     return level;
208   }
209 
210   static bool is_evac_allowed(Thread* thread) {
211     return evac_oom_scope_level(thread) > 0;
212   }
213 
214   // Offsets
215   static ByteSize satb_mark_queue_active_offset() {
216     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active();
217   }
218 
219   static ByteSize satb_mark_queue_index_offset() {
220     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index();
221   }
222 
223   static ByteSize satb_mark_queue_buffer_offset() {
224     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf();
225   }
226 
227   static ByteSize gc_state_offset() {
228     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _gc_state);
229   }
230 
231   static ByteSize disarmed_value_offset() {
232     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _disarmed_value);
233   }
234 };
235 
236 STATIC_ASSERT(sizeof(ShenandoahThreadLocalData) <= sizeof(GCThreadLocalData));
237 
238 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP