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 #ifndef SHARE_GC_SHARED_SLIDINGFORWARDING_INLINE_HPP
 26 #define SHARE_GC_SHARED_SLIDINGFORWARDING_INLINE_HPP
 27 
 28 #include "gc/shared/gc_globals.hpp"
 29 #include "gc/shared/slidingForwarding.hpp"
 30 #include "oops/markWord.hpp"
 31 #include "oops/oop.inline.hpp"
 32 #include "utilities/macros.hpp"
 33 
 34 inline bool SlidingForwarding::is_forwarded(oop obj) {
 35   return obj->is_forwarded();
 36 }
 37 
 38 inline bool SlidingForwarding::is_not_forwarded(oop obj) {
 39   return !obj->is_forwarded();
 40 }
 41 
 42 size_t SlidingForwarding::biased_region_index_containing(HeapWord* addr) {
 43   return (uintptr_t)addr >> _region_size_bytes_shift;
 44 }
 45 
 46 uintptr_t SlidingForwarding::encode_forwarding(HeapWord* from, HeapWord* to) {
 47   static_assert(NUM_TARGET_REGIONS == 2, "Only implemented for this amount");
 48 
 49   size_t from_reg_idx = biased_region_index_containing(from);
 50   HeapWord* to_region_base = (HeapWord*)((uintptr_t)to & _region_mask);
 51 
 52   HeapWord** base = &_biased_bases[0][from_reg_idx];
 53   uintptr_t alternate = 0;
 54   if (*base == to_region_base) {
 55     // Primary is good
 56   } else if (*base == UNUSED_BASE) {
 57     // Primary is free
 58     *base = to_region_base;
 59   } else {
 60     base = &_biased_bases[1][from_reg_idx];
 61     if (*base == to_region_base) {
 62       // Alternate is good
 63     } else if (*base == UNUSED_BASE) {
 64       // Alternate is free
 65       *base = to_region_base;
 66     } else {
 67       // Both primary and alternate are not fitting
 68       // This happens only in the following rare situations:
 69       // - In Serial GC, sometimes when compact-top switches spaces, because the
 70       //   region boudaries are virtual and objects can cross regions
 71       // - In G1 serial compaction, because tails of various compaction chains
 72       //   are distributed across the remainders of already compacted regions.
 73       return (1 << FALLBACK_SHIFT) | markWord::marked_value;
 74     }
 75     alternate = 1;
 76   }
 77 
 78   size_t offset = pointer_delta(to, to_region_base);
 79   assert(offset < _region_size_words, "Offset should be within the region. from: " PTR_FORMAT
 80          ", to: " PTR_FORMAT ", to_region_base: " PTR_FORMAT ", offset: " SIZE_FORMAT,
 81          p2i(from), p2i(to), p2i(to_region_base), offset);
 82 
 83   uintptr_t encoded = (offset << OFFSET_BITS_SHIFT) |
 84                       (alternate << ALT_REGION_SHIFT) |
 85                       markWord::marked_value;
 86 
 87   assert(to == decode_forwarding(from, encoded), "must be reversible");
 88   assert((encoded & ~MARK_LOWER_HALF_MASK) == 0, "must encode to lowest 32 bits");
 89   return encoded;
 90 }
 91 
 92 HeapWord* SlidingForwarding::decode_forwarding(HeapWord* from, uintptr_t encoded) {
 93   assert((encoded & markWord::lock_mask_in_place) == markWord::marked_value, "must be marked as forwarded");
 94   assert((encoded & FALLBACK_MASK) == 0, "must not be fallback-forwarded");
 95   assert((encoded & ~MARK_LOWER_HALF_MASK) == 0, "must decode from lowest 32 bits");
 96   size_t alternate = (encoded >> ALT_REGION_SHIFT) & right_n_bits(ALT_REGION_BITS);
 97   assert(alternate < NUM_TARGET_REGIONS, "Sanity");
 98   uintptr_t offset = (encoded >> OFFSET_BITS_SHIFT);
 99 
100   size_t from_idx = biased_region_index_containing(from);
101   HeapWord* base = _biased_bases[alternate][from_idx];
102   assert(base != UNUSED_BASE, "must not be unused base");
103   HeapWord* decoded = base + offset;
104   assert(decoded >= _heap_start,
105          "Address must be above heap start. encoded: " INTPTR_FORMAT ", alt_region: " SIZE_FORMAT ", base: " PTR_FORMAT,
106          encoded, alternate, p2i(base));
107 
108   return decoded;
109 }
110 
111 inline void SlidingForwarding::forward_to_impl(oop from, oop to) {
112   assert(_bases_table != nullptr, "call begin() before forwarding");
113 
114   markWord from_header = from->mark();
115   if (from_header.has_displaced_mark_helper()) {
116     from_header = from_header.displaced_mark_helper();
117   }
118 
119   HeapWord* from_hw = cast_from_oop<HeapWord*>(from);
120   HeapWord* to_hw   = cast_from_oop<HeapWord*>(to);
121   uintptr_t encoded = encode_forwarding(from_hw, to_hw);
122   markWord new_header = markWord((from_header.value() & ~MARK_LOWER_HALF_MASK) | encoded);
123   from->set_mark(new_header);
124 
125   if ((encoded & FALLBACK_MASK) != 0) {
126     fallback_forward_to(from_hw, to_hw);
127   }
128 }
129 
130 template <bool ALT_FWD>
131 inline void SlidingForwarding::forward_to(oop obj, oop fwd) {
132 #ifdef _LP64
133   if (ALT_FWD) {
134     assert(_bases_table != nullptr, "expect sliding forwarding initialized");
135     forward_to_impl(obj, fwd);
136     assert(forwardee<ALT_FWD>(obj) == fwd, "must be forwarded to correct forwardee");
137   } else
138 #endif
139   {
140     obj->forward_to(fwd);
141   }
142 }
143 
144 inline oop SlidingForwarding::forwardee_impl(oop from) {
145   assert(_bases_table != nullptr, "call begin() before asking for forwarding");
146 
147   markWord header = from->mark();
148   HeapWord* from_hw = cast_from_oop<HeapWord*>(from);
149   if ((header.value() & FALLBACK_MASK) != 0) {
150     HeapWord* to = fallback_forwardee(from_hw);
151     return cast_to_oop(to);
152   }
153   uintptr_t encoded = header.value() & MARK_LOWER_HALF_MASK;
154   HeapWord* to = decode_forwarding(from_hw, encoded);
155   return cast_to_oop(to);
156 }
157 
158 template <bool ALT_FWD>
159 inline oop SlidingForwarding::forwardee(oop obj) {
160 #ifdef _LP64
161   if (ALT_FWD) {
162     assert(_bases_table != nullptr, "expect sliding forwarding initialized");
163     return forwardee_impl(obj);
164   } else
165 #endif
166   {
167     return obj->forwardee();
168   }
169 }
170 
171 #endif // SHARE_GC_SHARED_SLIDINGFORWARDING_INLINE_HPP