Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/gc/shared/blockOffsetTable.cpp
40957 views
1
/*
2
* Copyright (c) 2000, 2019, 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
25
#include "precompiled.hpp"
26
#include "gc/shared/blockOffsetTable.inline.hpp"
27
#include "gc/shared/collectedHeap.inline.hpp"
28
#include "gc/shared/space.inline.hpp"
29
#include "memory/iterator.hpp"
30
#include "memory/universe.hpp"
31
#include "logging/log.hpp"
32
#include "oops/oop.inline.hpp"
33
#include "runtime/java.hpp"
34
#include "services/memTracker.hpp"
35
36
//////////////////////////////////////////////////////////////////////
37
// BlockOffsetSharedArray
38
//////////////////////////////////////////////////////////////////////
39
40
BlockOffsetSharedArray::BlockOffsetSharedArray(MemRegion reserved,
41
size_t init_word_size):
42
_reserved(reserved), _end(NULL)
43
{
44
size_t size = compute_size(reserved.word_size());
45
ReservedSpace rs(size);
46
if (!rs.is_reserved()) {
47
vm_exit_during_initialization("Could not reserve enough space for heap offset array");
48
}
49
50
MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
51
52
if (!_vs.initialize(rs, 0)) {
53
vm_exit_during_initialization("Could not reserve enough space for heap offset array");
54
}
55
_offset_array = (u_char*)_vs.low_boundary();
56
resize(init_word_size);
57
log_trace(gc, bot)("BlockOffsetSharedArray::BlockOffsetSharedArray: ");
58
log_trace(gc, bot)(" rs.base(): " INTPTR_FORMAT " rs.size(): " INTPTR_FORMAT " rs end(): " INTPTR_FORMAT,
59
p2i(rs.base()), rs.size(), p2i(rs.base() + rs.size()));
60
log_trace(gc, bot)(" _vs.low_boundary(): " INTPTR_FORMAT " _vs.high_boundary(): " INTPTR_FORMAT,
61
p2i(_vs.low_boundary()), p2i(_vs.high_boundary()));
62
}
63
64
void BlockOffsetSharedArray::resize(size_t new_word_size) {
65
assert(new_word_size <= _reserved.word_size(), "Resize larger than reserved");
66
size_t new_size = compute_size(new_word_size);
67
size_t old_size = _vs.committed_size();
68
size_t delta;
69
char* high = _vs.high();
70
_end = _reserved.start() + new_word_size;
71
if (new_size > old_size) {
72
delta = ReservedSpace::page_align_size_up(new_size - old_size);
73
assert(delta > 0, "just checking");
74
if (!_vs.expand_by(delta)) {
75
// Do better than this for Merlin
76
vm_exit_out_of_memory(delta, OOM_MMAP_ERROR, "offset table expansion");
77
}
78
assert(_vs.high() == high + delta, "invalid expansion");
79
} else {
80
delta = ReservedSpace::page_align_size_down(old_size - new_size);
81
if (delta == 0) return;
82
_vs.shrink_by(delta);
83
assert(_vs.high() == high - delta, "invalid expansion");
84
}
85
}
86
87
bool BlockOffsetSharedArray::is_card_boundary(HeapWord* p) const {
88
assert(p >= _reserved.start(), "just checking");
89
size_t delta = pointer_delta(p, _reserved.start());
90
return (delta & right_n_bits((int)BOTConstants::LogN_words)) == (size_t)NoBits;
91
}
92
93
94
//////////////////////////////////////////////////////////////////////
95
// BlockOffsetArray
96
//////////////////////////////////////////////////////////////////////
97
98
BlockOffsetArray::BlockOffsetArray(BlockOffsetSharedArray* array,
99
MemRegion mr, bool init_to_zero_) :
100
BlockOffsetTable(mr.start(), mr.end()),
101
_array(array)
102
{
103
assert(_bottom <= _end, "arguments out of order");
104
set_init_to_zero(init_to_zero_);
105
if (!init_to_zero_) {
106
// initialize cards to point back to mr.start()
107
set_remainder_to_point_to_start(mr.start() + BOTConstants::N_words, mr.end());
108
_array->set_offset_array(0, 0); // set first card to 0
109
}
110
}
111
112
113
// The arguments follow the normal convention of denoting
114
// a right-open interval: [start, end)
115
void
116
BlockOffsetArray::
117
set_remainder_to_point_to_start(HeapWord* start, HeapWord* end, bool reducing) {
118
119
check_reducing_assertion(reducing);
120
if (start >= end) {
121
// The start address is equal to the end address (or to
122
// the right of the end address) so there are not cards
123
// that need to be updated..
124
return;
125
}
126
127
// Write the backskip value for each region.
128
//
129
// offset
130
// card 2nd 3rd
131
// | +- 1st | |
132
// v v v v
133
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-
134
// |x|0|0|0|0|0|0|0|1|1|1|1|1|1| ... |1|1|1|1|2|2|2|2|2|2| ...
135
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-
136
// 11 19 75
137
// 12
138
//
139
// offset card is the card that points to the start of an object
140
// x - offset value of offset card
141
// 1st - start of first logarithmic region
142
// 0 corresponds to logarithmic value N_words + 0 and 2**(3 * 0) = 1
143
// 2nd - start of second logarithmic region
144
// 1 corresponds to logarithmic value N_words + 1 and 2**(3 * 1) = 8
145
// 3rd - start of third logarithmic region
146
// 2 corresponds to logarithmic value N_words + 2 and 2**(3 * 2) = 64
147
//
148
// integer below the block offset entry is an example of
149
// the index of the entry
150
//
151
// Given an address,
152
// Find the index for the address
153
// Find the block offset table entry
154
// Convert the entry to a back slide
155
// (e.g., with today's, offset = 0x81 =>
156
// back slip = 2**(3*(0x81 - N_words)) = 2**3) = 8
157
// Move back N (e.g., 8) entries and repeat with the
158
// value of the new entry
159
//
160
size_t start_card = _array->index_for(start);
161
size_t end_card = _array->index_for(end-1);
162
assert(start ==_array->address_for_index(start_card), "Precondition");
163
assert(end ==_array->address_for_index(end_card)+BOTConstants::N_words, "Precondition");
164
set_remainder_to_point_to_start_incl(start_card, end_card, reducing); // closed interval
165
}
166
167
168
// Unlike the normal convention in this code, the argument here denotes
169
// a closed, inclusive interval: [start_card, end_card], cf set_remainder_to_point_to_start()
170
// above.
171
void
172
BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t end_card, bool reducing) {
173
174
check_reducing_assertion(reducing);
175
if (start_card > end_card) {
176
return;
177
}
178
assert(start_card > _array->index_for(_bottom), "Cannot be first card");
179
assert(_array->offset_array(start_card-1) <= BOTConstants::N_words,
180
"Offset card has an unexpected value");
181
size_t start_card_for_region = start_card;
182
u_char offset = max_jubyte;
183
for (uint i = 0; i < BOTConstants::N_powers; i++) {
184
// -1 so that the the card with the actual offset is counted. Another -1
185
// so that the reach ends in this region and not at the start
186
// of the next.
187
size_t reach = start_card - 1 + (BOTConstants::power_to_cards_back(i+1) - 1);
188
offset = BOTConstants::N_words + i;
189
if (reach >= end_card) {
190
_array->set_offset_array(start_card_for_region, end_card, offset, reducing);
191
start_card_for_region = reach + 1;
192
break;
193
}
194
_array->set_offset_array(start_card_for_region, reach, offset, reducing);
195
start_card_for_region = reach + 1;
196
}
197
assert(start_card_for_region > end_card, "Sanity check");
198
DEBUG_ONLY(check_all_cards(start_card, end_card);)
199
}
200
201
// The card-interval [start_card, end_card] is a closed interval; this
202
// is an expensive check -- use with care and only under protection of
203
// suitable flag.
204
void BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) const {
205
206
if (end_card < start_card) {
207
return;
208
}
209
guarantee(_array->offset_array(start_card) == BOTConstants::N_words, "Wrong value in second card");
210
u_char last_entry = BOTConstants::N_words;
211
for (size_t c = start_card + 1; c <= end_card; c++ /* yeah! */) {
212
u_char entry = _array->offset_array(c);
213
guarantee(entry >= last_entry, "Monotonicity");
214
if (c - start_card > BOTConstants::power_to_cards_back(1)) {
215
guarantee(entry > BOTConstants::N_words, "Should be in logarithmic region");
216
}
217
size_t backskip = BOTConstants::entry_to_cards_back(entry);
218
size_t landing_card = c - backskip;
219
guarantee(landing_card >= (start_card - 1), "Inv");
220
if (landing_card >= start_card) {
221
guarantee(_array->offset_array(landing_card) <= entry, "Monotonicity");
222
} else {
223
guarantee(landing_card == (start_card - 1), "Tautology");
224
// Note that N_words is the maximum offset value
225
guarantee(_array->offset_array(landing_card) <= BOTConstants::N_words, "Offset value");
226
}
227
last_entry = entry; // remember for monotonicity test
228
}
229
}
230
231
232
void
233
BlockOffsetArray::alloc_block(HeapWord* blk_start, HeapWord* blk_end) {
234
assert(blk_start != NULL && blk_end > blk_start,
235
"phantom block");
236
single_block(blk_start, blk_end);
237
}
238
239
// Action_mark - update the BOT for the block [blk_start, blk_end).
240
// Current typical use is for splitting a block.
241
// Action_single - udpate the BOT for an allocation.
242
// Action_verify - BOT verification.
243
void
244
BlockOffsetArray::do_block_internal(HeapWord* blk_start,
245
HeapWord* blk_end,
246
Action action, bool reducing) {
247
assert(_sp->is_in_reserved(blk_start),
248
"reference must be into the space");
249
assert(_sp->is_in_reserved(blk_end-1),
250
"limit must be within the space");
251
// This is optimized to make the test fast, assuming we only rarely
252
// cross boundaries.
253
uintptr_t end_ui = (uintptr_t)(blk_end - 1);
254
uintptr_t start_ui = (uintptr_t)blk_start;
255
// Calculate the last card boundary preceding end of blk
256
intptr_t boundary_before_end = (intptr_t)end_ui;
257
clear_bits(boundary_before_end, right_n_bits((int)BOTConstants::LogN));
258
if (start_ui <= (uintptr_t)boundary_before_end) {
259
// blk starts at or crosses a boundary
260
// Calculate index of card on which blk begins
261
size_t start_index = _array->index_for(blk_start);
262
// Index of card on which blk ends
263
size_t end_index = _array->index_for(blk_end - 1);
264
// Start address of card on which blk begins
265
HeapWord* boundary = _array->address_for_index(start_index);
266
assert(boundary <= blk_start, "blk should start at or after boundary");
267
if (blk_start != boundary) {
268
// blk starts strictly after boundary
269
// adjust card boundary and start_index forward to next card
270
boundary += BOTConstants::N_words;
271
start_index++;
272
}
273
assert(start_index <= end_index, "monotonicity of index_for()");
274
assert(boundary <= (HeapWord*)boundary_before_end, "tautology");
275
switch (action) {
276
case Action_mark: {
277
if (init_to_zero()) {
278
_array->set_offset_array(start_index, boundary, blk_start, reducing);
279
break;
280
} // Else fall through to the next case
281
}
282
case Action_single: {
283
_array->set_offset_array(start_index, boundary, blk_start, reducing);
284
// We have finished marking the "offset card". We need to now
285
// mark the subsequent cards that this blk spans.
286
if (start_index < end_index) {
287
HeapWord* rem_st = _array->address_for_index(start_index) + BOTConstants::N_words;
288
HeapWord* rem_end = _array->address_for_index(end_index) + BOTConstants::N_words;
289
set_remainder_to_point_to_start(rem_st, rem_end, reducing);
290
}
291
break;
292
}
293
case Action_check: {
294
_array->check_offset_array(start_index, boundary, blk_start);
295
// We have finished checking the "offset card". We need to now
296
// check the subsequent cards that this blk spans.
297
check_all_cards(start_index + 1, end_index);
298
break;
299
}
300
default:
301
ShouldNotReachHere();
302
}
303
}
304
}
305
306
// The range [blk_start, blk_end) represents a single contiguous block
307
// of storage; modify the block offset table to represent this
308
// information; Right-open interval: [blk_start, blk_end)
309
// NOTE: this method does _not_ adjust _unallocated_block.
310
void
311
BlockOffsetArray::single_block(HeapWord* blk_start,
312
HeapWord* blk_end) {
313
do_block_internal(blk_start, blk_end, Action_single);
314
}
315
316
void BlockOffsetArray::verify() const {
317
// For each entry in the block offset table, verify that
318
// the entry correctly finds the start of an object at the
319
// first address covered by the block or to the left of that
320
// first address.
321
322
size_t next_index = 1;
323
size_t last_index = last_active_index();
324
325
// Use for debugging. Initialize to NULL to distinguish the
326
// first iteration through the while loop.
327
HeapWord* last_p = NULL;
328
HeapWord* last_start = NULL;
329
oop last_o = NULL;
330
331
while (next_index <= last_index) {
332
// Use an address past the start of the address for
333
// the entry.
334
HeapWord* p = _array->address_for_index(next_index) + 1;
335
if (p >= _end) {
336
// That's all of the allocated block table.
337
return;
338
}
339
// block_start() asserts that start <= p.
340
HeapWord* start = block_start(p);
341
// First check if the start is an allocated block and only
342
// then if it is a valid object.
343
oop o = cast_to_oop(start);
344
assert(!Universe::is_fully_initialized() ||
345
_sp->is_free_block(start) ||
346
oopDesc::is_oop_or_null(o), "Bad object was found");
347
next_index++;
348
last_p = p;
349
last_start = start;
350
last_o = o;
351
}
352
}
353
354
//////////////////////////////////////////////////////////////////////
355
// BlockOffsetArrayContigSpace
356
//////////////////////////////////////////////////////////////////////
357
358
HeapWord* BlockOffsetArrayContigSpace::block_start_unsafe(const void* addr) const {
359
assert(_array->offset_array(0) == 0, "objects can't cross covered areas");
360
361
// Otherwise, find the block start using the table.
362
assert(_bottom <= addr && addr < _end,
363
"addr must be covered by this Array");
364
size_t index = _array->index_for(addr);
365
// We must make sure that the offset table entry we use is valid. If
366
// "addr" is past the end, start at the last known one and go forward.
367
index = MIN2(index, _next_offset_index-1);
368
HeapWord* q = _array->address_for_index(index);
369
370
uint offset = _array->offset_array(index); // Extend u_char to uint.
371
while (offset > BOTConstants::N_words) {
372
// The excess of the offset from N_words indicates a power of Base
373
// to go back by.
374
size_t n_cards_back = BOTConstants::entry_to_cards_back(offset);
375
q -= (BOTConstants::N_words * n_cards_back);
376
assert(q >= _sp->bottom(), "Went below bottom!");
377
index -= n_cards_back;
378
offset = _array->offset_array(index);
379
}
380
while (offset == BOTConstants::N_words) {
381
assert(q >= _sp->bottom(), "Went below bottom!");
382
q -= BOTConstants::N_words;
383
index--;
384
offset = _array->offset_array(index);
385
}
386
assert(offset < BOTConstants::N_words, "offset too large");
387
q -= offset;
388
HeapWord* n = q;
389
390
while (n <= addr) {
391
debug_only(HeapWord* last = q); // for debugging
392
q = n;
393
n += _sp->block_size(n);
394
}
395
assert(q <= addr, "wrong order for current and arg");
396
assert(addr <= n, "wrong order for arg and next");
397
return q;
398
}
399
400
//
401
// _next_offset_threshold
402
// | _next_offset_index
403
// v v
404
// +-------+-------+-------+-------+-------+
405
// | i-1 | i | i+1 | i+2 | i+3 |
406
// +-------+-------+-------+-------+-------+
407
// ( ^ ]
408
// block-start
409
//
410
411
void BlockOffsetArrayContigSpace::alloc_block_work(HeapWord* blk_start,
412
HeapWord* blk_end) {
413
assert(blk_start != NULL && blk_end > blk_start,
414
"phantom block");
415
assert(blk_end > _next_offset_threshold,
416
"should be past threshold");
417
assert(blk_start <= _next_offset_threshold,
418
"blk_start should be at or before threshold");
419
assert(pointer_delta(_next_offset_threshold, blk_start) <= BOTConstants::N_words,
420
"offset should be <= BlockOffsetSharedArray::N");
421
assert(_sp->is_in_reserved(blk_start),
422
"reference must be into the space");
423
assert(_sp->is_in_reserved(blk_end-1),
424
"limit must be within the space");
425
assert(_next_offset_threshold ==
426
_array->_reserved.start() + _next_offset_index*BOTConstants::N_words,
427
"index must agree with threshold");
428
429
debug_only(size_t orig_next_offset_index = _next_offset_index;)
430
431
// Mark the card that holds the offset into the block. Note
432
// that _next_offset_index and _next_offset_threshold are not
433
// updated until the end of this method.
434
_array->set_offset_array(_next_offset_index,
435
_next_offset_threshold,
436
blk_start);
437
438
// We need to now mark the subsequent cards that this blk spans.
439
440
// Index of card on which blk ends.
441
size_t end_index = _array->index_for(blk_end - 1);
442
443
// Are there more cards left to be updated?
444
if (_next_offset_index + 1 <= end_index) {
445
HeapWord* rem_st = _array->address_for_index(_next_offset_index + 1);
446
// Calculate rem_end this way because end_index
447
// may be the last valid index in the covered region.
448
HeapWord* rem_end = _array->address_for_index(end_index) + BOTConstants::N_words;
449
set_remainder_to_point_to_start(rem_st, rem_end);
450
}
451
452
// _next_offset_index and _next_offset_threshold updated here.
453
_next_offset_index = end_index + 1;
454
// Calculate _next_offset_threshold this way because end_index
455
// may be the last valid index in the covered region.
456
_next_offset_threshold = _array->address_for_index(end_index) + BOTConstants::N_words;
457
assert(_next_offset_threshold >= blk_end, "Incorrect offset threshold");
458
459
#ifdef ASSERT
460
// The offset can be 0 if the block starts on a boundary. That
461
// is checked by an assertion above.
462
size_t start_index = _array->index_for(blk_start);
463
HeapWord* boundary = _array->address_for_index(start_index);
464
assert((_array->offset_array(orig_next_offset_index) == 0 &&
465
blk_start == boundary) ||
466
(_array->offset_array(orig_next_offset_index) > 0 &&
467
_array->offset_array(orig_next_offset_index) <= BOTConstants::N_words),
468
"offset array should have been set");
469
for (size_t j = orig_next_offset_index + 1; j <= end_index; j++) {
470
assert(_array->offset_array(j) > 0 &&
471
_array->offset_array(j) <= (u_char) (BOTConstants::N_words+BOTConstants::N_powers-1),
472
"offset array should have been set");
473
}
474
#endif
475
}
476
477
HeapWord* BlockOffsetArrayContigSpace::initialize_threshold() {
478
_next_offset_index = _array->index_for(_bottom);
479
_next_offset_index++;
480
_next_offset_threshold =
481
_array->address_for_index(_next_offset_index);
482
return _next_offset_threshold;
483
}
484
485
void BlockOffsetArrayContigSpace::zero_bottom_entry() {
486
size_t bottom_index = _array->index_for(_bottom);
487
_array->set_offset_array(bottom_index, 0);
488
}
489
490
size_t BlockOffsetArrayContigSpace::last_active_index() const {
491
return _next_offset_index == 0 ? 0 : _next_offset_index - 1;
492
}
493
494