1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef BERBERIS_BASE_POINTER_AND_COUNTER_H_ 18 #define BERBERIS_BASE_POINTER_AND_COUNTER_H_ 19 20 #include <cstdint> 21 22 #include "berberis/base/bit_util.h" 23 #include "berberis/base/checks.h" 24 25 namespace berberis { 26 27 // Pack aligned pointer and counter into uint64_t for atomic handling. 28 template <typename T, size_t kAlign = alignof(T)> 29 struct PointerAndCounter { 30 #if defined(__LP64__) 31 // 64-bit pointers and size_t. Use 48 bits for address and save alignment bits. 32 // [counter][pointer-without-align-bits] 33 // bit: 63 0 34 static_assert(sizeof(T*) == 8, "wrong pointer size"); 35 static const size_t kPointerBits = 48; 36 static const size_t kAlignBits = BitUtilLog2(kAlign); 37 #else 38 // 32-bit pointers and size_t. KISS. 39 // [counter][pointer] 40 // bit: 63 32 31 0 41 static_assert(sizeof(T*) == 4, "wrong pointer size"); 42 static const size_t kPointerBits = 32; 43 static const size_t kAlignBits = 0; 44 #endif 45 46 static const size_t kRealPointerBits = kPointerBits - kAlignBits; 47 static const size_t kCounterBits = 64 - kRealPointerBits; 48 49 static const uint64_t kRealPointerMask = uint64_t(-1) >> kCounterBits; 50 51 static const uint64_t kMaxCounter = uint64_t(1) << kCounterBits; 52 53 // ATTENTION: counter might get truncated! PackUnsafePointerAndCounter54 static uint64_t PackUnsafe(T* p, uint64_t cnt) { 55 uintptr_t ptr = reinterpret_cast<uintptr_t>(p); 56 return (static_cast<uint64_t>(ptr) >> kAlignBits) | (cnt << kRealPointerBits); 57 } 58 PackPointerAndCounter59 static uint64_t Pack(T* p, uint64_t cnt) { 60 CHECK_GT(kMaxCounter, cnt); 61 return PackUnsafe(p, cnt); 62 } 63 UnpackPointerPointerAndCounter64 static T* UnpackPointer(uint64_t v) { 65 uintptr_t ptr = static_cast<uintptr_t>((v & kRealPointerMask) << kAlignBits); 66 return reinterpret_cast<T*>(ptr); 67 } 68 UnpackCounterPointerAndCounter69 static uint64_t UnpackCounter(uint64_t v) { return v >> kRealPointerBits; } 70 }; 71 72 } // namespace berberis 73 74 #endif // BERBERIS_BASE_POINTER_AND_COUNTER_H_ 75