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/shenandoah/shenandoahBarrierSet.hpp"
30 #include "gc/shenandoah/shenandoahCodeRoots.hpp"
31 #include "gc/shenandoah/shenandoahSATBMarkQueueSet.hpp"
32 #include "runtime/thread.hpp"
33 #include "utilities/debug.hpp"
34 #include "utilities/sizes.hpp"
35
36 class ShenandoahThreadLocalData {
37 public:
38 static const uint INVALID_WORKER_ID = uint(-1);
39
40 private:
41 char _gc_state;
42 char _oom_during_evac;
43 ShenandoahSATBMarkQueue _satb_mark_queue;
44 PLAB* _gclab;
45 size_t _gclab_size;
46 uint _worker_id;
47 bool _force_satb_flush;
48 int _disarmed_value;
49
50 ShenandoahThreadLocalData() :
51 _gc_state(0),
52 _oom_during_evac(0),
53 _satb_mark_queue(&ShenandoahBarrierSet::satb_mark_queue_set()),
54 _gclab(NULL),
55 _gclab_size(0),
56 _worker_id(INVALID_WORKER_ID),
57 _force_satb_flush(false),
58 _disarmed_value(0) {
59
60 // At least on x86_64, nmethod entry barrier encodes _disarmed_value offset
61 // in instruction as disp8 immed
62 assert(in_bytes(disarmed_value_offset()) < 128, "Offset range check");
63 }
64
65 ~ShenandoahThreadLocalData() {
66 if (_gclab != NULL) {
67 delete _gclab;
68 }
69 }
70
71 static ShenandoahThreadLocalData* data(Thread* thread) {
72 assert(UseShenandoahGC, "Sanity");
73 return thread->gc_data<ShenandoahThreadLocalData>();
74 }
75
76 static ByteSize satb_mark_queue_offset() {
77 return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _satb_mark_queue);
78 }
79
80 public:
81 static void create(Thread* thread) {
82 new (data(thread)) ShenandoahThreadLocalData();
83 }
84
85 static void destroy(Thread* thread) {
86 data(thread)->~ShenandoahThreadLocalData();
87 }
88
89 static SATBMarkQueue& satb_mark_queue(Thread* thread) {
90 return data(thread)->_satb_mark_queue;
91 }
92
93 static bool is_oom_during_evac(Thread* thread) {
94 return (data(thread)->_oom_during_evac & 1) == 1;
95 }
96
97 static void set_oom_during_evac(Thread* thread, bool oom) {
98 if (oom) {
99 data(thread)->_oom_during_evac |= 1;
100 } else {
101 data(thread)->_oom_during_evac &= ~1;
102 }
103 }
104
105 static void set_gc_state(Thread* thread, char gc_state) {
106 data(thread)->_gc_state = gc_state;
107 }
108
109 static char gc_state(Thread* thread) {
110 return data(thread)->_gc_state;
111 }
112
113 static void set_worker_id(Thread* thread, uint id) {
114 assert(thread->is_Worker_thread(), "Must be a worker thread");
115 data(thread)->_worker_id = id;
116 }
117
118 static uint worker_id(Thread* thread) {
119 assert(thread->is_Worker_thread(), "Must be a worker thread");
120 return data(thread)->_worker_id;
121 }
122
123 static void set_force_satb_flush(Thread* thread, bool v) {
124 data(thread)->_force_satb_flush = v;
134 data(thread)->_gclab = new PLAB(PLAB::min_size());
135 data(thread)->_gclab_size = 0;
136 }
137
138 static PLAB* gclab(Thread* thread) {
139 return data(thread)->_gclab;
140 }
141
142 static size_t gclab_size(Thread* thread) {
143 return data(thread)->_gclab_size;
144 }
145
146 static void set_gclab_size(Thread* thread, size_t v) {
147 data(thread)->_gclab_size = v;
148 }
149
150 static void set_disarmed_value(Thread* thread, int value) {
151 data(thread)->_disarmed_value = value;
152 }
153
154 #ifdef ASSERT
155 static void set_evac_allowed(Thread* thread, bool evac_allowed) {
156 if (evac_allowed) {
157 data(thread)->_oom_during_evac |= 2;
158 } else {
159 data(thread)->_oom_during_evac &= ~2;
160 }
161 }
162
163 static bool is_evac_allowed(Thread* thread) {
164 return (data(thread)->_oom_during_evac & 2) == 2;
165 }
166 #endif
167
168 // Offsets
169 static ByteSize satb_mark_queue_active_offset() {
170 return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active();
171 }
172
173 static ByteSize satb_mark_queue_index_offset() {
174 return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index();
175 }
176
177 static ByteSize satb_mark_queue_buffer_offset() {
178 return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf();
179 }
180
181 static ByteSize gc_state_offset() {
182 return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _gc_state);
183 }
184
185 static ByteSize disarmed_value_offset() {
186 return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _disarmed_value);
|
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/shenandoah/shenandoahBarrierSet.hpp"
30 #include "gc/shenandoah/shenandoahCodeRoots.hpp"
31 #include "gc/shenandoah/shenandoahSATBMarkQueueSet.hpp"
32 #include "runtime/thread.hpp"
33 #include "utilities/debug.hpp"
34 #include "utilities/sizes.hpp"
35
36 /* Highest bit indicates if current thread encountered OOM
37 * Remaining bits represent evacuation scope nesting level
38 */
39 typedef struct {
40 uint8_t _nesting_level : 7;
41 uint8_t _is_evac_oom : 1;
42 } ShenandoahEvacOOMState;
43
44 STATIC_ASSERT(sizeof(ShenandoahEvacOOMState) == sizeof(char));
45
46 class ShenandoahThreadLocalData {
47 public:
48 static const uint INVALID_WORKER_ID = uint(-1);
49
50 private:
51 char _gc_state;
52 ShenandoahEvacOOMState _oom_during_evac;
53 ShenandoahSATBMarkQueue _satb_mark_queue;
54 PLAB* _gclab;
55 size_t _gclab_size;
56 uint _worker_id;
57 bool _force_satb_flush;
58 int _disarmed_value;
59
60 ShenandoahThreadLocalData() :
61 _gc_state(0),
62 _satb_mark_queue(&ShenandoahBarrierSet::satb_mark_queue_set()),
63 _gclab(NULL),
64 _gclab_size(0),
65 _worker_id(INVALID_WORKER_ID),
66 _force_satb_flush(false),
67 _disarmed_value(0) {
68 _oom_during_evac._nesting_level = 0;
69 _oom_during_evac._is_evac_oom = 0;
70
71 // At least on x86_64, nmethod entry barrier encodes _disarmed_value offset
72 // in instruction as disp8 immed
73 assert(in_bytes(disarmed_value_offset()) < 128, "Offset range check");
74 }
75
76 ~ShenandoahThreadLocalData() {
77 if (_gclab != NULL) {
78 delete _gclab;
79 }
80 }
81
82 static ShenandoahThreadLocalData* data(Thread* thread) {
83 assert(UseShenandoahGC, "Sanity");
84 return thread->gc_data<ShenandoahThreadLocalData>();
85 }
86
87 static ByteSize satb_mark_queue_offset() {
88 return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _satb_mark_queue);
89 }
90
91 public:
92 static void create(Thread* thread) {
93 new (data(thread)) ShenandoahThreadLocalData();
94 }
95
96 static void destroy(Thread* thread) {
97 data(thread)->~ShenandoahThreadLocalData();
98 }
99
100 static SATBMarkQueue& satb_mark_queue(Thread* thread) {
101 return data(thread)->_satb_mark_queue;
102 }
103
104 static void set_gc_state(Thread* thread, char gc_state) {
105 data(thread)->_gc_state = gc_state;
106 }
107
108 static char gc_state(Thread* thread) {
109 return data(thread)->_gc_state;
110 }
111
112 static void set_worker_id(Thread* thread, uint id) {
113 assert(thread->is_Worker_thread(), "Must be a worker thread");
114 data(thread)->_worker_id = id;
115 }
116
117 static uint worker_id(Thread* thread) {
118 assert(thread->is_Worker_thread(), "Must be a worker thread");
119 return data(thread)->_worker_id;
120 }
121
122 static void set_force_satb_flush(Thread* thread, bool v) {
123 data(thread)->_force_satb_flush = v;
133 data(thread)->_gclab = new PLAB(PLAB::min_size());
134 data(thread)->_gclab_size = 0;
135 }
136
137 static PLAB* gclab(Thread* thread) {
138 return data(thread)->_gclab;
139 }
140
141 static size_t gclab_size(Thread* thread) {
142 return data(thread)->_gclab_size;
143 }
144
145 static void set_gclab_size(Thread* thread, size_t v) {
146 data(thread)->_gclab_size = v;
147 }
148
149 static void set_disarmed_value(Thread* thread, int value) {
150 data(thread)->_disarmed_value = value;
151 }
152
153 // Evacuation OOM handling
154 static bool is_oom_during_evac(Thread* thread) {
155 return data(thread)->_oom_during_evac._is_evac_oom == 1;
156 }
157
158 static void set_oom_during_evac(Thread* thread, bool oom) {
159 if (oom) {
160 data(thread)->_oom_during_evac._is_evac_oom = 1;
161 } else {
162 data(thread)->_oom_during_evac._is_evac_oom = 0;
163 }
164 }
165
166 static uint8_t evac_oom_scope_level(Thread* thread) {
167 return data(thread)->_oom_during_evac._nesting_level;
168 }
169
170 // Push the scope one level deeper, return previous level
171 static uint8_t push_evac_oom_scope(Thread* thread) {
172 uint8_t level = evac_oom_scope_level(thread);
173 assert(level < 127, "Overflow nesting level");
174 data(thread)->_oom_during_evac._nesting_level = level + 1;
175 return level;
176 }
177
178 // Pop the scope by one level, return previous level
179 static uint8_t pop_evac_oom_scope(Thread* thread) {
180 uint8_t level = evac_oom_scope_level(thread);
181 assert(level > 0, "Underflow nesting level");
182 data(thread)->_oom_during_evac._nesting_level = level - 1;
183 return level;
184 }
185
186 static bool is_evac_allowed(Thread* thread) {
187 return evac_oom_scope_level(thread) > 0;
188 }
189
190 // Offsets
191 static ByteSize satb_mark_queue_active_offset() {
192 return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active();
193 }
194
195 static ByteSize satb_mark_queue_index_offset() {
196 return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index();
197 }
198
199 static ByteSize satb_mark_queue_buffer_offset() {
200 return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf();
201 }
202
203 static ByteSize gc_state_offset() {
204 return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _gc_state);
205 }
206
207 static ByteSize disarmed_value_offset() {
208 return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _disarmed_value);
|