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   // Thread-local mirror for global GC state
 48   char _gc_state;
 49 
 50   SATBMarkQueue           _satb_mark_queue;
 51 
 52   // Current active CardTable's byte_map_base for this thread.
 53   CardTable::CardValue*   _card_table;
 54 
 55   // Thread-local allocation buffer for object evacuations.
 56   // In generational mode, it is exclusive to the young generation.
 57   PLAB* _gclab;
 58   size_t _gclab_size;
 59 
 60   // Thread-local allocation buffer only used in generational mode.
 61   // Used both by mutator threads and by GC worker threads
 62   // for evacuations within the old generation and
 63   // for promotions from the young generation into the old generation.
 64   ShenandoahPLAB* _shenandoah_plab;
 65 
 66   ShenandoahEvacuationStats* _evacuation_stats;
 67 
 68   Atomic<HeapWord*> _invisible_root;
 69   Atomic<size_t> _invisible_root_word_size;
 70 
 71   ShenandoahThreadLocalData();
 72   ~ShenandoahThreadLocalData();
 73 
 74   static ShenandoahThreadLocalData* data(Thread* thread) {
 75     assert(UseShenandoahGC, "Sanity");
 76     return thread->gc_data<ShenandoahThreadLocalData>();
 77   }
 78 
 79   static ByteSize satb_mark_queue_offset() {
 80     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _satb_mark_queue);
 81   }
 82 
 83 public:
 84   static void create(Thread* thread) {
 85     new (data(thread)) ShenandoahThreadLocalData();
 86   }
 87 
 88   static void destroy(Thread* thread) {
 89     data(thread)->~ShenandoahThreadLocalData();
 90   }
 91 
 92   static SATBMarkQueue& satb_mark_queue(Thread* thread) {
 93     return data(thread)->_satb_mark_queue;
 94   }
 95 
 96   static void set_gc_state(Thread* thread, char gc_state) {
 97     ShenandoahThreadLocalData* d = data(thread);
 98     d->_gc_state = gc_state;
 99   }
100 
101   static char gc_state(Thread* thread) {
102     return data(thread)->_gc_state;
103   }
104 
105   static bool is_gc_state(Thread* thread, ShenandoahHeap::GCState state) {
106     return (gc_state(thread) & state) != 0;
107   }
108 
109   static bool is_gc_state(ShenandoahHeap::GCState state) {
110     return is_gc_state(Thread::current(), state);
111   }
112 
113   static void set_card_table(Thread* thread, CardTable::CardValue* ct) {
114     assert(ct != nullptr, "trying to set thread local card_table pointer to nullptr.");
115     data(thread)->_card_table = ct;
116   }
117 
118   static CardTable::CardValue* card_table(Thread* thread) {
119     CardTable::CardValue* ct = data(thread)->_card_table;
120     assert(ct != nullptr, "returning a null thread local card_table pointer.");
121     return ct;
122   }
123 
124   static void initialize_gclab(Thread* thread) {
125     assert(data(thread)->_gclab == nullptr, "Only initialize once");
126     data(thread)->_gclab = new PLAB(PLAB::min_size());
127     data(thread)->_gclab_size = 0;
128 
129     if (ShenandoahHeap::heap()->mode()->is_generational()) {
130       data(thread)->_shenandoah_plab = new ShenandoahPLAB();
131     }
132   }
133 
134   static PLAB* gclab(Thread* thread) {
135     return data(thread)->_gclab;
136   }
137 
138   static size_t gclab_size(Thread* thread) {
139     return data(thread)->_gclab_size;
140   }
141 
142   static void set_gclab_size(Thread* thread, size_t v) {
143     data(thread)->_gclab_size = v;
144   }
145 
146   static void begin_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
147     data(thread)->_evacuation_stats->begin_evacuation(bytes, from, to);
148   }
149 
150   static void end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) {
151     data(thread)->_evacuation_stats->end_evacuation(bytes, from, to);
152   }
153 
154   static ShenandoahEvacuationStats* evacuation_stats(Thread* thread) {
155     return data(thread)->_evacuation_stats;
156   }
157 
158   static ShenandoahPLAB* shenandoah_plab(Thread* thread) {
159     return data(thread)->_shenandoah_plab;
160   }
161 
162   // Offsets
163   static ByteSize satb_mark_queue_index_offset() {
164     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index();
165   }
166 
167   static ByteSize satb_mark_queue_buffer_offset() {
168     return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf();
169   }
170 
171   static ByteSize gc_state_offset() {
172     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _gc_state);
173   }
174 
175   static ByteSize card_table_offset() {
176     return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _card_table);
177   }
178 
179   // invisible root are the partially initialized obj array set by ShenandoahObjArrayAllocator
180   static void set_invisible_root(Thread* thread, HeapWord* invisible_root, size_t word_size) {
181     data(thread)->_invisible_root.store_relaxed(invisible_root);
182     data(thread)->_invisible_root_word_size.store_relaxed(word_size);
183   }
184 
185   static void clear_invisible_root(Thread* thread) {
186     data(thread)->_invisible_root.store_relaxed(nullptr);
187     data(thread)->_invisible_root_word_size.store_relaxed(0);
188   }
189 
190   static HeapWord* get_invisible_root(Thread* thread) {
191     return data(thread)->_invisible_root.load_relaxed();
192   }
193 
194   static size_t get_invisible_root_word_size(Thread* thread) {
195     return data(thread)->_invisible_root_word_size.load_relaxed();
196   }
197 };
198 
199 STATIC_ASSERT(sizeof(ShenandoahThreadLocalData) <= sizeof(GCThreadLocalData));
200 
201 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHTHREADLOCALDATA_HPP