1 /* 2 * Copyright Amazon.com Inc. 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/fullGCForwarding.hpp" 27 #include "logging/log.hpp" 28 #include "nmt/memTag.hpp" 29 #include "utilities/ostream.hpp" 30 #include "utilities/concurrentHashTable.inline.hpp" 31 #include "utilities/fastHash.hpp" 32 #include "utilities/powerOfTwo.hpp" 33 34 static uintx hash(HeapWord* const& addr) { 35 uint64_t val = reinterpret_cast<uint64_t>(addr); 36 uint32_t hash = FastHash::get_hash32((uint32_t)val, (uint32_t)(val >> 32)); 37 return hash; 38 } 39 40 struct ForwardingEntry { 41 HeapWord* _from; 42 HeapWord* _to; 43 ForwardingEntry(HeapWord* from, HeapWord* to) : _from(from), _to(to) {} 44 }; 45 46 struct FallbackTableConfig { 47 using Value = ForwardingEntry; 48 static uintx get_hash(Value const& entry, bool* is_dead) { 49 return hash(entry._from); 50 } 51 static void* allocate_node(void* context, size_t size, Value const& value) { 52 return AllocateHeap(size, mtGC); 53 } 54 static void free_node(void* context, void* memory, Value const& value) { 55 FreeHeap(memory); 56 } 57 }; 58 59 class FallbackTable : public ConcurrentHashTable<FallbackTableConfig, mtGC> { 60 61 }; 62 63 class FallbackTableLookup : public StackObj { 64 ForwardingEntry const _entry; 65 public: 66 explicit FallbackTableLookup(HeapWord* from) : _entry(from, nullptr) {} 67 uintx get_hash() const { 68 return hash(_entry._from); 69 } 70 bool equals(ForwardingEntry* value) { 71 return _entry._from == value->_from; 72 } 73 bool is_dead(ForwardingEntry* value) { return false; } 74 }; 75 76 // We cannot use 0, because that may already be a valid base address in zero-based heaps. 77 // 0x1 is safe because heap base addresses must be aligned by much larger alignment 78 HeapWord* const FullGCForwarding::UNUSED_BASE = reinterpret_cast<HeapWord*>(0x1); 79 80 HeapWord* FullGCForwarding::_heap_start = nullptr; 81 size_t FullGCForwarding::_heap_start_region_bias = 0; 82 size_t FullGCForwarding::_num_regions = 0; 83 uintptr_t FullGCForwarding::_region_mask = 0; 84 HeapWord** FullGCForwarding::_biased_bases = nullptr; 85 HeapWord** FullGCForwarding::_bases_table = nullptr; 86 FallbackTable* FullGCForwarding::_fallback_table = nullptr; 87 #ifndef PRODUCT 88 volatile uint64_t FullGCForwarding::_num_forwardings = 0; 89 volatile uint64_t FullGCForwarding::_num_fallback_forwardings = 0; 90 #endif 91 92 void FullGCForwarding::initialize(MemRegion heap) { 93 #ifdef _LP64 94 _heap_start = heap.start(); 95 96 size_t rounded_heap_size = round_up_power_of_2(heap.byte_size()); 97 98 _num_regions = (rounded_heap_size / BytesPerWord) / BLOCK_SIZE_WORDS; 99 100 _heap_start_region_bias = (uintptr_t)_heap_start >> BLOCK_SIZE_BYTES_SHIFT; 101 _region_mask = ~((uintptr_t(1) << BLOCK_SIZE_BYTES_SHIFT) - 1); 102 103 assert(_bases_table == nullptr, "should not be initialized yet"); 104 assert(_fallback_table == nullptr, "should not be initialized yet"); 105 #endif 106 } 107 108 void FullGCForwarding::begin() { 109 #ifdef _LP64 110 assert(_bases_table == nullptr, "should not be initialized yet"); 111 assert(_fallback_table == nullptr, "should not be initialized yet"); 112 113 _fallback_table = new FallbackTable(); 114 115 #ifndef PRODUCT 116 _num_forwardings = 0; 117 _num_fallback_forwardings = 0; 118 #endif 119 120 size_t max = _num_regions; 121 _bases_table = NEW_C_HEAP_ARRAY(HeapWord*, max, mtGC); 122 HeapWord** biased_start = _bases_table - _heap_start_region_bias; 123 _biased_bases = biased_start; 124 for (size_t i = 0; i < max; i++) { 125 _bases_table[i] = UNUSED_BASE; 126 } 127 #endif 128 } 129 130 void FullGCForwarding::end() { 131 #ifndef PRODUCT 132 log_info(gc)("Total forwardings: " UINT64_FORMAT ", fallback forwardings: " UINT64_FORMAT 133 ", ratio: %f, memory used by fallback table: " SIZE_FORMAT "%s, memory used by bases table: " SIZE_FORMAT "%s", 134 _num_forwardings, _num_fallback_forwardings, (float)_num_forwardings/(float)_num_fallback_forwardings, 135 byte_size_in_proper_unit(_fallback_table->get_mem_size(Thread::current())), 136 proper_unit_for_byte_size(_fallback_table->get_mem_size(Thread::current())), 137 byte_size_in_proper_unit(sizeof(HeapWord*) * _num_regions), 138 proper_unit_for_byte_size(sizeof(HeapWord*) * _num_regions)); 139 #endif 140 #ifdef _LP64 141 assert(_bases_table != nullptr, "should be initialized"); 142 FREE_C_HEAP_ARRAY(HeapWord*, _bases_table); 143 _bases_table = nullptr; 144 delete _fallback_table; 145 _fallback_table = nullptr; 146 #endif 147 } 148 149 void FullGCForwarding::fallback_forward_to(HeapWord* from, HeapWord* to) { 150 assert(to != nullptr, "no null forwarding"); 151 assert(_fallback_table != nullptr, "should be initialized"); 152 FallbackTableLookup lookup_f(from); 153 ForwardingEntry entry(from, to); 154 auto found_f = [&](ForwardingEntry* found) { 155 // If dupe has been found, override it with new value. 156 // This is also called when new entry is succussfully inserted. 157 if (found->_to != to) { 158 found->_to = to; 159 } 160 }; 161 Thread* current_thread = Thread::current(); 162 bool grow; 163 bool added = _fallback_table->insert_get(current_thread, lookup_f, entry, found_f, &grow); 164 NOT_PRODUCT(Atomic::inc(&_num_fallback_forwardings);) 165 #ifdef ASSERT 166 assert(fallback_forwardee(from) != nullptr, "must have entered forwarding"); 167 assert(fallback_forwardee(from) == to, "forwarding must be correct, added: %s, from: " PTR_FORMAT ", to: " PTR_FORMAT ", fwd: " PTR_FORMAT, BOOL_TO_STR(added), p2i(from), p2i(to), p2i(fallback_forwardee(from))); 168 #endif 169 if (grow) { 170 _fallback_table->grow(current_thread); 171 tty->print_cr("grow fallback table to size: " SIZE_FORMAT " bytes", 172 _fallback_table->get_mem_size(current_thread)); 173 } 174 } 175 176 HeapWord* FullGCForwarding::fallback_forwardee(HeapWord* from) { 177 assert(_fallback_table != nullptr, "fallback table must be present"); 178 HeapWord* result; 179 FallbackTableLookup lookup_f(from); 180 auto found_f = [&](ForwardingEntry* found) { 181 result = found->_to; 182 }; 183 bool found = _fallback_table->get(Thread::current(), lookup_f, found_f); 184 assert(found, "something must have been found"); 185 assert(result != nullptr, "must have found forwarding"); 186 return result; 187 }