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 private:
 40   char _gc_state;
 41   // Evacuation OOM state
 42   uint8_t                 _oom_scope_nesting_level;
 43   bool                    _oom_during_evac;
 44   SATBMarkQueue           _satb_mark_queue;
 45   PLAB* _gclab;
 46   size_t _gclab_size;
 47   int  _disarmed_value;
 48   double _paced_time;
 49 
 50   ShenandoahThreadLocalData() :
 51     _gc_state(0),
 52     _oom_scope_nesting_level(0),
 53     _oom_during_evac(false),
 54     _satb_mark_queue(&ShenandoahBarrierSet::satb_mark_queue_set()),
 55     _gclab(NULL),
 56     _gclab_size(0),
 57     _disarmed_value(0),
 58     _paced_time(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 void set_gc_state(Thread* thread, char gc_state) {
 94     data(thread)->_gc_state = gc_state;
 95   }
 96 
 97   static char gc_state(Thread* thread) {
 98     return data(thread)->_gc_state;
 99   }
100 
101   static void initialize_gclab(Thread* thread) {
102     assert (thread->is_Java_thread() || thread->is_Worker_thread(), "Only Java and GC worker threads are allowed to get GCLABs");
103     assert(data(thread)->_gclab == NULL, "Only initialize once");
104     data(thread)->_gclab = new PLAB(PLAB::min_size());
105     data(thread)->_gclab_size = 0;
106   }
107 
108   static PLAB* gclab(Thread* thread) {
109     return data(thread)->_gclab;
110   }
111 
112   static size_t gclab_size(Thread* thread) {
113     return data(thread)->_gclab_size;
114   }
115 
116   static void set_gclab_size(Thread* thread, size_t v) {
117     data(thread)->_gclab_size = v;
118   }
119 
120   static void add_paced_time(Thread* thread, double v) {
121     data(thread)->_paced_time += v;
122   }
123 
124   static double paced_time(Thread* thread) {
125     return data(thread)->_paced_time;
126   }
127 
128   static void reset_paced_time(Thread* thread) {
129     data(thread)->_paced_time = 0;
130   }
131 
132   static void set_disarmed_value(Thread* thread, int value) {
133     data(thread)->_disarmed_value = value;
134   }
135 
136   // Evacuation OOM handling
137   static bool is_oom_during_evac(Thread* thread) {
138     return data(thread)->_oom_during_evac;
139   }
140 
141   static void set_oom_during_evac(Thread* thread, bool oom) {
142     data(thread)->_oom_during_evac = oom;
143   }
144 
145   static uint8_t evac_oom_scope_level(Thread* thread) {
146     return data(thread)->_oom_scope_nesting_level;
147   }
148 
149   // Push the scope one level deeper, return previous level
150   static uint8_t push_evac_oom_scope(Thread* thread) {
151     uint8_t level = evac_oom_scope_level(thread);
152     assert(level < 254, "Overflow nesting level"); // UINT8_MAX = 255
153     data(thread)->_oom_scope_nesting_level = level + 1;
154     return level;
155   }
156 
157   // Pop the scope by one level, return previous level
158   static uint8_t pop_evac_oom_scope(Thread* thread) {
159     uint8_t level = evac_oom_scope_level(thread);
160     assert(level > 0, "Underflow nesting level");
161     data(thread)->_oom_scope_nesting_level = level - 1;
162     return level;
163   }
164 
165   static bool is_evac_allowed(Thread* thread) {
166     return evac_oom_scope_level(thread) > 0;
167   }
168 
169   // Offsets
170   static ByteSize satb_mark_queue_active_offset() {
171     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active();
172   }
173 
174   static ByteSize satb_mark_queue_index_offset() {
175     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index();
176   }
177 
178   static ByteSize satb_mark_queue_buffer_offset() {
179     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf();
180   }
181 
182   static ByteSize gc_state_offset() {
183     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _gc_state);
184   }
185 
186   static ByteSize disarmed_value_offset() {
187     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _disarmed_value);
188   }
189 };
190 
191 STATIC_ASSERT(sizeof(ShenandoahThreadLocalData) <= sizeof(GCThreadLocalData));
192 
193 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP