1 /*
  2  * Copyright (c) 2017, 2021, 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 #ifndef SHARE_OOPS_COMPRESSEDOOPS_INLINE_HPP
 26 #define SHARE_OOPS_COMPRESSEDOOPS_INLINE_HPP
 27 
 28 #include "oops/compressedOops.hpp"
 29 
 30 #include "memory/universe.hpp"
 31 #include "oops/oop.hpp"
 32 #include "utilities/align.hpp"
 33 #include "utilities/globalDefinitions.hpp"
 34 
 35 // Functions for encoding and decoding compressed oops.
 36 // If the oops are compressed, the type passed to these overloaded functions
 37 // is narrowOop.  All functions are overloaded so they can be called by
 38 // template functions without conditionals (the compiler instantiates via
 39 // the right type and inlines the appropriate code).
 40 
 41 // Algorithm for encoding and decoding oops from 64 bit pointers to 32 bit
 42 // offset from the heap base.  Saving the check for null can save instructions
 43 // in inner GC loops so these are separated.
 44 
 45 inline oop CompressedOops::decode_raw_not_null(narrowOop v) {
 46   assert(!is_null(v), "narrow oop value can never be zero");
 47   return decode_raw(v);
 48 }
 49 
 50 inline oop CompressedOops::decode_raw(narrowOop v) {
 51   return cast_to_oop((uintptr_t)base() + ((uintptr_t)v << shift()));
 52 }
 53 
 54 inline oop CompressedOops::decode_not_null(narrowOop v) {
 55   assert(!is_null(v), "narrow oop value can never be zero");
 56   oop result = decode_raw(v);
 57   assert(is_object_aligned(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
 58   assert(Universe::is_in_heap(result), "object not in heap " PTR_FORMAT, p2i((void*) result));
 59   return result;
 60 }
 61 
 62 inline oop CompressedOops::decode(narrowOop v) {
 63   return is_null(v) ? (oop)NULL : decode_not_null(v);
 64 }
 65 
 66 inline narrowOop CompressedOops::encode_not_null(oop v) {
 67   assert(!is_null(v), "oop value can never be zero");
 68   assert(is_object_aligned(v), "address not aligned: " PTR_FORMAT, p2i((void*)v));
 69   assert(is_in(v), "address not in heap range: " PTR_FORMAT, p2i((void*)v));
 70   uint64_t  pd = (uint64_t)(pointer_delta((void*)v, (void*)base(), 1));
 71   assert(OopEncodingHeapMax > pd, "change encoding max if new encoding");
 72   narrowOop result = narrow_oop_cast(pd >> shift());
 73   assert(decode_raw(result) == v, "reversibility");
 74   return result;
 75 }
 76 
 77 inline narrowOop CompressedOops::encode(oop v) {
 78   return is_null(v) ? narrowOop::null : encode_not_null(v);
 79 }
 80 
 81 inline oop CompressedOops::decode_not_null(oop v) {
 82   assert(Universe::is_in_heap(v), "object not in heap " PTR_FORMAT, p2i((void*) v));
 83   return v;
 84 }
 85 
 86 inline oop CompressedOops::decode(oop v) {
 87   assert(Universe::is_in_heap_or_null(v), "object not in heap " PTR_FORMAT, p2i((void*) v));
 88   return v;
 89 }
 90 
 91 inline narrowOop CompressedOops::encode_not_null(narrowOop v) {
 92   return v;
 93 }
 94 
 95 inline narrowOop CompressedOops::encode(narrowOop v) {
 96   return v;
 97 }
 98 
 99 inline uint32_t CompressedOops::narrow_oop_value(oop o) {
100   return narrow_oop_value(encode(o));
101 }
102 
103 inline uint32_t CompressedOops::narrow_oop_value(narrowOop o) {
104   return static_cast<uint32_t>(o);
105 }
106 
107 template<typename T>
108 inline narrowOop CompressedOops::narrow_oop_cast(T i) {
109   static_assert(std::is_integral<T>::value, "precondition");
110   uint32_t narrow_value = static_cast<uint32_t>(i);
111   // Ensure no bits lost in conversion to uint32_t.
112   assert(i == static_cast<T>(narrow_value), "narrowOop overflow");
113   return static_cast<narrowOop>(narrow_value);
114 }
115 
116 static inline bool check_alignment(Klass* v) {
117   return (intptr_t)v % KlassAlignmentInBytes == 0;
118 }
119 
120 inline Klass* CompressedKlassPointers::decode_raw(narrowKlass v) {
121   return decode_raw(v, base());
122 }
123 
124 inline Klass* CompressedKlassPointers::decode_raw(narrowKlass v, address narrow_base) {
125   return (Klass*)(void*)((uintptr_t)narrow_base +((uintptr_t)v << shift()));
126 }
127 
128 inline Klass* CompressedKlassPointers::decode_not_null(narrowKlass v) {
129   return decode_not_null(v, base());
130 }
131 
132 inline Klass* CompressedKlassPointers::decode_not_null(narrowKlass v, address narrow_base) {
133   assert(!is_null(v), "narrow klass value can never be zero");
134   Klass* result = decode_raw(v, narrow_base);
135   assert(check_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
136   return result;
137 }
138 
139 inline Klass* CompressedKlassPointers::decode(narrowKlass v) {
140   return is_null(v) ? (Klass*)NULL : decode_not_null(v);
141 }
142 
143 inline narrowKlass CompressedKlassPointers::encode_not_null(Klass* v) {
144   return encode_not_null(v, base());
145 }
146 
147 inline narrowKlass CompressedKlassPointers::encode_not_null(Klass* v, address narrow_base) {
148   assert(!is_null(v), "klass value can never be zero");
149   assert(check_alignment(v), "Address not aligned");
150   uint64_t pd = (uint64_t)(pointer_delta((void*)v, narrow_base, 1));
151   assert(KlassEncodingMetaspaceMax > pd, "change encoding max if new encoding");
152   uint64_t result = pd >> shift();
153   assert((result & CONST64(0xffffffff00000000)) == 0, "narrow klass pointer overflow");
154   assert(decode_not_null(result, narrow_base) == v, "reversibility");
155   return (narrowKlass)result;
156 }
157 
158 inline narrowKlass CompressedKlassPointers::encode(Klass* v) {
159   return is_null(v) ? (narrowKlass)0 : encode_not_null(v);
160 }
161 
162 #endif // SHARE_OOPS_COMPRESSEDOOPS_INLINE_HPP