1 /*
  2  * Copyright (c) 2018, 2022, Red Hat, Inc. All rights reserved.
  3  * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP
 27 #define SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP
 28 
 29 #include "gc/shared/gc_globals.hpp"
 30 #include "gc/shared/gcThreadLocalData.hpp"
 31 #include "gc/shared/plab.hpp"
 32 #include "gc/shenandoah/mode/shenandoahMode.hpp"
 33 #include "gc/shenandoah/shenandoahAffiliation.hpp"
 34 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
 35 #include "gc/shenandoah/shenandoahCardTable.hpp"
 36 #include "gc/shenandoah/shenandoahCodeRoots.hpp"
 37 #include "gc/shenandoah/shenandoahEvacTracker.hpp"
 38 #include "gc/shenandoah/shenandoahGenerationalHeap.hpp"
 39 #include "gc/shenandoah/shenandoahPLAB.hpp"
 40 #include "gc/shenandoah/shenandoahSATBMarkQueueSet.hpp"
 41 #include "runtime/javaThread.hpp"
 42 #include "utilities/debug.hpp"
 43 #include "utilities/sizes.hpp"
 44 
 45 class ShenandoahThreadLocalData {
 46 private:
 47   char _gc_state;
 48   // Evacuation OOM state
 49   uint8_t                 _oom_scope_nesting_level;
 50   bool                    _oom_during_evac;
 51 
 52   SATBMarkQueue           _satb_mark_queue;
 53 
 54   // Current active CardTable's byte_map_base for this thread.
 55   CardTable::CardValue*   _card_table;
 56 
 57   // Thread-local allocation buffer for object evacuations.
 58   // In generational mode, it is exclusive to the young generation.
 59   PLAB* _gclab;
 60   size_t _gclab_size;
 61 
 62   // Thread-local allocation buffer only used in generational mode.
 63   // Used both by mutator threads and by GC worker threads
 64   // for evacuations within the old generation and
 65   // for promotions from the young generation into the old generation.
 66   ShenandoahPLAB* _shenandoah_plab;
 67 
 68   ShenandoahEvacuationStats* _evacuation_stats;
 69 
 70   ShenandoahThreadLocalData();
 71   ~ShenandoahThreadLocalData();
 72 
 73   static ShenandoahThreadLocalData* data(Thread* thread) {
 74     assert(UseShenandoahGC, "Sanity");
 75     return thread->gc_data<ShenandoahThreadLocalData>();
 76   }
 77 
 78   static ByteSize satb_mark_queue_offset() {
 79     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _satb_mark_queue);
 80   }
 81 
 82 public:
 83   static void create(Thread* thread) {
 84     new (data(thread)) ShenandoahThreadLocalData();
 85   }
 86 
 87   static void destroy(Thread* thread) {
 88     data(thread)->~ShenandoahThreadLocalData();
 89   }
 90 
 91   static SATBMarkQueue& satb_mark_queue(Thread* thread) {
 92     return data(thread)->_satb_mark_queue;
 93   }
 94 
 95   static void set_gc_state(Thread* thread, char gc_state) {
 96     data(thread)->_gc_state = gc_state;
 97   }
 98 
 99   static char gc_state(Thread* thread) {
100     return data(thread)->_gc_state;
101   }
102 
103   static bool is_gc_state(Thread* thread, ShenandoahHeap::GCState state) {
104     return (gc_state(thread) & state) != 0;
105   }
106 
107   static bool is_gc_state(ShenandoahHeap::GCState state) {
108     return is_gc_state(Thread::current(), state);
109   }
110 
111   static void set_card_table(Thread* thread, CardTable::CardValue* ct) {
112     assert(ct != nullptr, "trying to set thread local card_table pointer to nullptr.");
113     data(thread)->_card_table = ct;
114   }
115 
116   static CardTable::CardValue* card_table(Thread* thread) {
117     CardTable::CardValue* ct = data(thread)->_card_table;
118     assert(ct != nullptr, "returning a null thread local card_table pointer.");
119     return ct;
120   }
121 
122   static void initialize_gclab(Thread* thread) {
123     assert(data(thread)->_gclab == nullptr, "Only initialize once");
124     data(thread)->_gclab = new PLAB(PLAB::min_size());
125     data(thread)->_gclab_size = 0;
126 
127     if (ShenandoahHeap::heap()->mode()->is_generational()) {
128       data(thread)->_shenandoah_plab = new ShenandoahPLAB();
129     }
130   }
131 
132   static PLAB* gclab(Thread* thread) {
133     return data(thread)->_gclab;
134   }
135 
136   static size_t gclab_size(Thread* thread) {
137     return data(thread)->_gclab_size;
138   }
139 
140   static void set_gclab_size(Thread* thread, size_t v) {
141     data(thread)->_gclab_size = v;
142   }
143 
144   static void begin_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
145     data(thread)->_evacuation_stats->begin_evacuation(bytes, from, to);
146   }
147 
148   static void end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
149     data(thread)->_evacuation_stats->end_evacuation(bytes, from, to);
150   }
151 
152   static ShenandoahEvacuationStats* evacuation_stats(Thread* thread) {
153     return data(thread)->_evacuation_stats;
154   }
155 
156   static ShenandoahPLAB* shenandoah_plab(Thread* thread) {
157     return data(thread)->_shenandoah_plab;
158   }
159 
160   // Evacuation OOM handling
161   static bool is_oom_during_evac(Thread* thread) {
162     return data(thread)->_oom_during_evac;
163   }
164 
165   static void set_oom_during_evac(Thread* thread, bool oom) {
166     data(thread)->_oom_during_evac = oom;
167   }
168 
169   static uint8_t evac_oom_scope_level(Thread* thread) {
170     return data(thread)->_oom_scope_nesting_level;
171   }
172 
173   // Push the scope one level deeper, return previous level
174   static uint8_t push_evac_oom_scope(Thread* thread) {
175     uint8_t level = evac_oom_scope_level(thread);
176     assert(level < 254, "Overflow nesting level"); // UINT8_MAX = 255
177     data(thread)->_oom_scope_nesting_level = level + 1;
178     return level;
179   }
180 
181   // Pop the scope by one level, return previous level
182   static uint8_t pop_evac_oom_scope(Thread* thread) {
183     uint8_t level = evac_oom_scope_level(thread);
184     assert(level > 0, "Underflow nesting level");
185     data(thread)->_oom_scope_nesting_level = level - 1;
186     return level;
187   }
188 
189   static bool is_evac_allowed(Thread* thread) {
190     return evac_oom_scope_level(thread) > 0;
191   }
192 
193   // Offsets
194   static ByteSize satb_mark_queue_index_offset() {
195     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index();
196   }
197 
198   static ByteSize satb_mark_queue_buffer_offset() {
199     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf();
200   }
201 
202   static ByteSize gc_state_offset() {
203     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _gc_state);
204   }
205 
206   static ByteSize card_table_offset() {
207     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _card_table);
208   }
209 };
210 
211 STATIC_ASSERT(sizeof(ShenandoahThreadLocalData) <= sizeof(GCThreadLocalData));
212 
213 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP