1/*
2 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. 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#ifndef SHARE_GC_Z_ZVALUE_HPP
25#define SHARE_GC_Z_ZVALUE_HPP
26
27#include "memory/allocation.hpp"
28#include "gc/z/zCPU.hpp"
29#include "gc/z/zGlobals.hpp"
30#include "gc/z/zNUMA.hpp"
31#include "gc/z/zThread.hpp"
32#include "gc/z/zUtils.hpp"
33#include "utilities/align.hpp"
34
35template <typename S>
36class ZValueStorage : public AllStatic {
37private:
38 static uintptr_t _top;
39 static uintptr_t _end;
40
41public:
42 static const size_t offset = 4 * K;
43
44 static uintptr_t alloc(size_t size) {
45 guarantee(size <= offset, "Allocation too large");
46
47 // Allocate entry in existing memory block
48 const uintptr_t addr = align_up(_top, S::alignment());
49 _top = addr + size;
50
51 if (_top < _end) {
52 // Success
53 return addr;
54 }
55
56 // Allocate new block of memory
57 const size_t block_alignment = offset;
58 const size_t block_size = offset * S::count();
59 _top = ZUtils::alloc_aligned(block_alignment, block_size);
60 _end = _top + offset;
61
62 // Retry allocation
63 return alloc(size);
64 }
65};
66
67template <typename T> uintptr_t ZValueStorage<T>::_end = 0;
68template <typename T> uintptr_t ZValueStorage<T>::_top = 0;
69
70class ZContendedStorage : public ZValueStorage<ZContendedStorage> {
71public:
72 static size_t alignment() {
73 return ZCacheLineSize;
74 }
75
76 static uint32_t count() {
77 return 1;
78 }
79
80 static uint32_t id() {
81 return 0;
82 }
83};
84
85class ZPerCPUStorage : public ZValueStorage<ZPerCPUStorage> {
86public:
87 static size_t alignment() {
88 return sizeof(uintptr_t);
89 }
90
91 static uint32_t count() {
92 return ZCPU::count();
93 }
94
95 static uint32_t id() {
96 return ZCPU::id();
97 }
98};
99
100class ZPerNUMAStorage : public ZValueStorage<ZPerNUMAStorage> {
101public:
102 static size_t alignment() {
103 return sizeof(uintptr_t);
104 }
105
106 static uint32_t count() {
107 return ZNUMA::count();
108 }
109
110 static uint32_t id() {
111 return ZNUMA::id();
112 }
113};
114
115class ZPerWorkerStorage : public ZValueStorage<ZPerWorkerStorage> {
116public:
117 static size_t alignment() {
118 return sizeof(uintptr_t);
119 }
120
121 static uint32_t count() {
122 return MAX2(ParallelGCThreads, ConcGCThreads);
123 }
124
125 static uint32_t id() {
126 return ZThread::worker_id();
127 }
128};
129
130template <typename S, typename T>
131class ZValueIterator;
132
133template <typename S, typename T>
134class ZValue : public CHeapObj<mtGC> {
135private:
136 const uintptr_t _addr;
137
138 uintptr_t value_addr(uint32_t value_id) const {
139 return _addr + (value_id * S::offset);
140 }
141
142public:
143 ZValue() :
144 _addr(S::alloc(sizeof(T))) {
145 // Initialize all instances
146 ZValueIterator<S, T> iter(this);
147 for (T* addr; iter.next(&addr);) {
148 ::new (addr) T;
149 }
150 }
151
152 ZValue(const T& value) :
153 _addr(S::alloc(sizeof(T))) {
154 // Initialize all instances
155 ZValueIterator<S, T> iter(this);
156 for (T* addr; iter.next(&addr);) {
157 ::new (addr) T(value);
158 }
159 }
160
161 // Not implemented
162 ZValue(const ZValue<S, T>& value);
163 ZValue<S, T>& operator=(const ZValue<S, T>& value);
164
165 const T* addr(uint32_t value_id = S::id()) const {
166 return reinterpret_cast<const T*>(value_addr(value_id));
167 }
168
169 T* addr(uint32_t value_id = S::id()) {
170 return reinterpret_cast<T*>(value_addr(value_id));
171 }
172
173 const T& get(uint32_t value_id = S::id()) const {
174 return *addr(value_id);
175 }
176
177 T& get(uint32_t value_id = S::id()) {
178 return *addr(value_id);
179 }
180
181 void set(const T& value, uint32_t value_id = S::id()) {
182 get(value_id) = value;
183 }
184
185 void set_all(const T& value) {
186 ZValueIterator<S, T> iter(this);
187 for (T* addr; iter.next(&addr);) {
188 *addr = value;
189 }
190 }
191};
192
193template <typename T>
194class ZContended : public ZValue<ZContendedStorage, T> {
195public:
196 ZContended() :
197 ZValue<ZContendedStorage, T>() {}
198
199 ZContended(const T& value) :
200 ZValue<ZContendedStorage, T>(value) {}
201
202 using ZValue<ZContendedStorage, T>::operator=;
203};
204
205template <typename T>
206class ZPerCPU : public ZValue<ZPerCPUStorage, T> {
207public:
208 ZPerCPU() :
209 ZValue<ZPerCPUStorage, T>() {}
210
211 ZPerCPU(const T& value) :
212 ZValue<ZPerCPUStorage, T>(value) {}
213
214 using ZValue<ZPerCPUStorage, T>::operator=;
215};
216
217template <typename T>
218class ZPerNUMA : public ZValue<ZPerNUMAStorage, T> {
219public:
220 ZPerNUMA() :
221 ZValue<ZPerNUMAStorage, T>() {}
222
223 ZPerNUMA(const T& value) :
224 ZValue<ZPerNUMAStorage, T>(value) {}
225
226 using ZValue<ZPerNUMAStorage, T>::operator=;
227};
228
229template <typename T>
230class ZPerWorker : public ZValue<ZPerWorkerStorage, T> {
231public:
232 ZPerWorker() :
233 ZValue<ZPerWorkerStorage, T>() {}
234
235 ZPerWorker(const T& value) :
236 ZValue<ZPerWorkerStorage, T>(value) {}
237
238 using ZValue<ZPerWorkerStorage, T>::operator=;
239};
240
241template <typename S, typename T>
242class ZValueIterator {
243private:
244 ZValue<S, T>* const _value;
245 uint32_t _value_id;
246
247public:
248 ZValueIterator(ZValue<S, T>* value) :
249 _value(value),
250 _value_id(0) {}
251
252 bool next(T** value) {
253 if (_value_id < S::count()) {
254 *value = _value->addr(_value_id++);
255 return true;
256 }
257 return false;
258 }
259};
260
261template <typename T>
262class ZPerCPUIterator : public ZValueIterator<ZPerCPUStorage, T> {
263public:
264 ZPerCPUIterator(ZPerCPU<T>* value) :
265 ZValueIterator<ZPerCPUStorage, T>(value) {}
266};
267
268template <typename T>
269class ZPerNUMAIterator : public ZValueIterator<ZPerNUMAStorage, T> {
270public:
271 ZPerNUMAIterator(ZPerNUMA<T>* value) :
272 ZValueIterator<ZPerNUMAStorage, T>(value) {}
273};
274
275template <typename T>
276class ZPerWorkerIterator : public ZValueIterator<ZPerWorkerStorage, T> {
277public:
278 ZPerWorkerIterator(ZPerWorker<T>* value) :
279 ZValueIterator<ZPerWorkerStorage, T>(value) {}
280};
281
282template <typename S, typename T>
283class ZValueConstIterator {
284private:
285 const ZValue<S, T>* const _value;
286 uint32_t _value_id;
287
288public:
289 ZValueConstIterator(const ZValue<S, T>* value) :
290 _value(value),
291 _value_id(0) {}
292
293 bool next(const T** value) {
294 if (_value_id < S::count()) {
295 *value = _value->addr(_value_id++);
296 return true;
297 }
298 return false;
299 }
300};
301
302template <typename T>
303class ZPerCPUConstIterator : public ZValueConstIterator<ZPerCPUStorage, T> {
304public:
305 ZPerCPUConstIterator(const ZPerCPU<T>* value) :
306 ZValueConstIterator<ZPerCPUStorage, T>(value) {}
307};
308
309template <typename T>
310class ZPerNUMAConstIterator : public ZValueConstIterator<ZPerNUMAStorage, T> {
311public:
312 ZPerNUMAConstIterator(const ZPerNUMA<T>* value) :
313 ZValueConstIterator<ZPerNUMAStorage, T>(value) {}
314};
315
316template <typename T>
317class ZPerWorkerConstIterator : public ZValueConstIterator<ZPerWorkerStorage, T> {
318public:
319 ZPerWorkerConstIterator(const ZPerWorker<T>* value) :
320 ZValueConstIterator<ZPerWorkerStorage, T>(value) {}
321};
322
323#endif // SHARE_GC_Z_ZVALUE_HPP
324