1 /*
  2  * Copyright (c) 2021, 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 #include "precompiled.hpp"
 27 #include "gc/shared/gc_globals.hpp"
 28 #include "gc/shared/slidingForwarding.hpp"
 29 #include "utilities/ostream.hpp"
 30 #include "utilities/powerOfTwo.hpp"
 31 
 32 // We cannot use 0, because that may already be a valid base address in zero-based heaps.
 33 // 0x1 is safe because heap base addresses must be aligned by much larger alignment
 34 HeapWord* const SlidingForwarding::UNUSED_BASE = reinterpret_cast<HeapWord*>(0x1);
 35 
 36 HeapWord* SlidingForwarding::_heap_start = nullptr;
 37 size_t SlidingForwarding::_region_size_words = 0;
 38 size_t SlidingForwarding::_heap_start_region_bias = 0;
 39 size_t SlidingForwarding::_num_regions = 0;
 40 uint SlidingForwarding::_region_size_bytes_shift = 0;
 41 uintptr_t SlidingForwarding::_region_mask = 0;
 42 HeapWord** SlidingForwarding::_biased_bases[SlidingForwarding::NUM_TARGET_REGIONS] = { nullptr, nullptr };
 43 HeapWord** SlidingForwarding::_bases_table = nullptr;
 44 SlidingForwarding::FallbackTable* SlidingForwarding::_fallback_table = nullptr;
 45 
 46 void SlidingForwarding::initialize(MemRegion heap, size_t region_size_words) {
 47 #ifdef _LP64
 48   if (UseAltGCForwarding) {
 49     _heap_start = heap.start();
 50 
 51     // If the heap is small enough to fit directly into the available offset bits,
 52     // and we are running Serial GC, we can treat the whole heap as a single region
 53     // if it happens to be aligned to allow biasing.
 54     size_t rounded_heap_size = round_up_power_of_2(heap.byte_size());
 55 
 56     if (UseSerialGC && (heap.word_size() <= (1 << NUM_OFFSET_BITS)) &&
 57         is_aligned((uintptr_t)_heap_start, rounded_heap_size)) {
 58       _num_regions = 1;
 59       _region_size_words = heap.word_size();
 60       _region_size_bytes_shift = log2i_exact(rounded_heap_size);
 61     } else {
 62       _num_regions = align_up(pointer_delta(heap.end(), heap.start()), region_size_words) / region_size_words;
 63       _region_size_words = region_size_words;
 64       _region_size_bytes_shift = log2i_exact(_region_size_words) + LogHeapWordSize;
 65     }
 66     _heap_start_region_bias = (uintptr_t)_heap_start >> _region_size_bytes_shift;
 67     _region_mask = ~((uintptr_t(1) << _region_size_bytes_shift) - 1);
 68 
 69     guarantee((_heap_start_region_bias << _region_size_bytes_shift) == (uintptr_t)_heap_start, "must be aligned: _heap_start_region_bias: " SIZE_FORMAT ", _region_size_byte_shift: %u, _heap_start: " PTR_FORMAT, _heap_start_region_bias, _region_size_bytes_shift, p2i(_heap_start));
 70 
 71     assert(_region_size_words >= 1, "regions must be at least a word large");
 72     assert(_bases_table == nullptr, "should not be initialized yet");
 73     assert(_fallback_table == nullptr, "should not be initialized yet");
 74   }
 75 #endif
 76 }
 77 
 78 void SlidingForwarding::begin() {
 79 #ifdef _LP64
 80   if (UseAltGCForwarding) {
 81     assert(_bases_table == nullptr, "should not be initialized yet");
 82     assert(_fallback_table == nullptr, "should not be initialized yet");
 83 
 84     size_t max = _num_regions * NUM_TARGET_REGIONS;
 85     _bases_table = NEW_C_HEAP_ARRAY(HeapWord*, max, mtGC);
 86     HeapWord** biased_start = _bases_table - _heap_start_region_bias;
 87     _biased_bases[0] = biased_start;
 88     _biased_bases[1] = biased_start + _num_regions;
 89     for (size_t i = 0; i < max; i++) {
 90       _bases_table[i] = UNUSED_BASE;
 91     }
 92   }
 93 #endif
 94 }
 95 
 96 void SlidingForwarding::end() {
 97 #ifdef _LP64
 98   if (UseAltGCForwarding) {
 99     assert(_bases_table != nullptr, "should be initialized");
100     FREE_C_HEAP_ARRAY(HeapWord*, _bases_table);
101     _bases_table = nullptr;
102     delete _fallback_table;
103     _fallback_table = nullptr;
104   }
105 #endif
106 }
107 
108 void SlidingForwarding::fallback_forward_to(HeapWord* from, HeapWord* to) {
109   if (_fallback_table == nullptr) {
110     _fallback_table = new (mtGC) FallbackTable();
111   }
112   _fallback_table->put_when_absent(from, to);
113 }
114 
115 HeapWord* SlidingForwarding::fallback_forwardee(HeapWord* from) {
116   assert(_fallback_table != nullptr, "fallback table must be present");
117   HeapWord** found = _fallback_table->get(from);
118   if (found != nullptr) {
119     return *found;
120   } else {
121     return nullptr;
122   }
123 }