1 /*
  2  * Copyright (c) 2021, Red Hat, Inc. 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_SHARED_SLIDINGFORWARDING_INLINE_HPP
 25 #define SHARE_GC_SHARED_SLIDINGFORWARDING_INLINE_HPP
 26 
 27 #include "gc/shared/slidingForwarding.hpp"
 28 #include "oops/markWord.hpp"
 29 #include "oops/oop.inline.hpp"
 30 
 31 #ifdef _LP64
 32 size_t SlidingForwarding::region_index_containing(HeapWord* addr) const {
 33   assert(addr >= _heap_start, "sanity: addr: " PTR_FORMAT " heap base: " PTR_FORMAT, p2i(addr), p2i(_heap_start));
 34   size_t index = ((size_t) (addr - _heap_start)) >> _region_size_words_shift;
 35   assert(index < _num_regions, "Region index is in bounds: " PTR_FORMAT, p2i(addr));
 36   return index;
 37 }
 38 
 39 bool SlidingForwarding::region_contains(HeapWord* region_base, HeapWord* addr) const {
 40   return uintptr_t(addr - region_base) < (ONE << _region_size_words_shift);
 41 }
 42 
 43 
 44 uintptr_t SlidingForwarding::encode_forwarding(HeapWord* original, HeapWord* target) {
 45   size_t orig_idx = region_index_containing(original);
 46   size_t base_table_idx = orig_idx * 2;
 47   size_t target_idx = region_index_containing(target);
 48   HeapWord* encode_base;
 49   uintptr_t region_idx;
 50   for (region_idx = 0; region_idx < NUM_REGIONS; region_idx++) {
 51     encode_base = _target_base_table[base_table_idx + region_idx];
 52     if (encode_base == UNUSED_BASE) {
 53       encode_base = _heap_start + target_idx * (ONE << _region_size_words_shift);
 54       _target_base_table[base_table_idx + region_idx] = encode_base;
 55       break;
 56     } else if (region_contains(encode_base, target)) {
 57       break;
 58     }
 59   }
 60   if (region_idx >= NUM_REGIONS) {
 61     tty->print_cr("target: " PTR_FORMAT, p2i(target));
 62     for (region_idx = 0; region_idx < NUM_REGIONS; region_idx++) {
 63       tty->print_cr("region_idx: " INTPTR_FORMAT ", encode_base: " PTR_FORMAT, region_idx, p2i(_target_base_table[base_table_idx + region_idx]));
 64     }
 65   }
 66   assert(region_idx < NUM_REGIONS, "need to have found an encoding base");
 67   assert(target >= encode_base, "target must be above encode base, target:" PTR_FORMAT ", encoded_base: " PTR_FORMAT ",  target_idx: " SIZE_FORMAT ", heap start: " PTR_FORMAT ", region_idx: " INTPTR_FORMAT,
 68          p2i(target), p2i(encode_base), target_idx, p2i(_heap_start), region_idx);
 69   assert(region_contains(encode_base, target), "region must contain target: original: " PTR_FORMAT ", target: " PTR_FORMAT ", encode_base: " PTR_FORMAT ", region_idx: " INTPTR_FORMAT, p2i(original), p2i(target), p2i(encode_base), region_idx);
 70   uintptr_t encoded = (((uintptr_t)(target - encode_base)) << COMPRESSED_BITS_SHIFT) |
 71                       (region_idx << BASE_SHIFT) | markWord::marked_value;
 72   assert(target == decode_forwarding(original, encoded), "must be reversible");
 73   return encoded;
 74 }
 75 
 76 HeapWord* SlidingForwarding::decode_forwarding(HeapWord* original, uintptr_t encoded) const {
 77   assert((encoded & markWord::marked_value) == markWord::marked_value, "must be marked as forwarded");
 78   size_t orig_idx = region_index_containing(original);
 79   size_t region_idx = (encoded >> BASE_SHIFT) & right_n_bits(NUM_REGION_BITS);
 80   size_t base_table_idx = orig_idx * 2 + region_idx;
 81   HeapWord* decoded = _target_base_table[base_table_idx] + (encoded >> COMPRESSED_BITS_SHIFT);
 82   assert(decoded >= _heap_start, "must be above heap start, encoded: " INTPTR_FORMAT ", region_idx: " SIZE_FORMAT ", base: " PTR_FORMAT, encoded, region_idx, p2i(_target_base_table[base_table_idx]));
 83   return decoded;
 84 }
 85 #endif
 86 
 87 void SlidingForwarding::forward_to(oop original, oop target) {
 88 #ifdef _LP64
 89   markWord header = original->mark();
 90   if (header.has_displaced_mark_helper()) {
 91     header = header.displaced_mark_helper();
 92   }
 93   uintptr_t encoded = encode_forwarding(cast_from_oop<HeapWord*>(original), cast_from_oop<HeapWord*>(target));
 94   assert((encoded & markWord::klass_mask_in_place) == 0, "encoded forwardee must not overlap with Klass*: " PTR_FORMAT, encoded);
 95   header = markWord((header.value() & markWord::klass_mask_in_place) | encoded);
 96   original->set_mark(header);
 97 #else
 98   original->forward_to(target);
 99 #endif
100 }
101 
102 oop SlidingForwarding::forwardee(oop original) const {
103 #ifdef _LP64
104   markWord header = original->mark();
105   uintptr_t encoded = header.value() & ~markWord::klass_mask_in_place;
106   HeapWord* forwardee = decode_forwarding(cast_from_oop<HeapWord*>(original), encoded);
107   return cast_to_oop(forwardee);
108 #else
109   return original->forwardee();
110 #endif
111 }
112 
113 #endif // SHARE_GC_SHARED_SLIDINGFORWARDING_INLINE_HPP