//===--- FlaggedPointer.h - Explicit pointer tagging container --*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the FlaggedPointer class. // //===----------------------------------------------------------------------===// // #ifndef SWIFT_BASIC_FLAGGEDPOINTER_H #define SWIFT_BASIC_FLAGGEDPOINTER_H #include #include #include "llvm/Support/Compiler.h" #include "llvm/Support/PointerLikeTypeTraits.h" namespace swift { /// This class implements a pair of a pointer and boolean flag. /// Like PointerIntPair, it represents this by mangling a bit into the low part /// of the pointer, taking advantage of pointer alignment. Unlike /// PointerIntPair, you must specify the bit position explicitly, instead of /// automatically placing an integer into the highest bits possible. /// /// Composing this with `PointerIntPair` is not allowed. template > class FlaggedPointer { intptr_t Value; static_assert(PtrTraits::NumLowBitsAvailable > 0, "Not enough bits to store flag at this position"); enum : uintptr_t { FlagMask = (uintptr_t)1 << BitPosition, PointerBitMask = ~FlagMask }; public: FlaggedPointer() : Value(0) {} FlaggedPointer(PointerTy PtrVal, bool FlagVal) { setPointerAndFlag(PtrVal, FlagVal); } explicit FlaggedPointer(PointerTy PtrVal) { initWithPointer(PtrVal); } /// Returns the underlying pointer with the flag bit masked out. PointerTy getPointer() const { return PtrTraits::getFromVoidPointer( reinterpret_cast(Value & PointerBitMask)); } void setPointer(PointerTy PtrVal) { intptr_t PtrWord = reinterpret_cast( PtrTraits::getAsVoidPointer(PtrVal)); assert((PtrWord & ~PointerBitMask) == 0 && "Pointer is not sufficiently aligned"); Value = PtrWord | (Value & ~PointerBitMask); } bool getFlag() const { return (bool)(Value & FlagMask); } void setFlag(bool FlagVal) { intptr_t FlagWord = static_cast(FlagVal); Value &= ~FlagMask; Value |= FlagWord << BitPosition; } /// Set the pointer value and assert if it overlaps with /// the flag's bit position. void initWithPointer(PointerTy PtrVal) { intptr_t PtrWord = reinterpret_cast( PtrTraits::getAsVoidPointer(PtrVal)); assert((PtrWord & ~PointerBitMask) == 0 && "Pointer is not sufficiently aligned"); Value = PtrWord; } /// Set the pointer value, set the flag, and assert /// if the pointer's value would overlap with the flag's /// bit position. void setPointerAndFlag(PointerTy PtrVal, bool FlagVal) { intptr_t PtrWord = reinterpret_cast( PtrTraits::getAsVoidPointer(PtrVal)); assert((PtrWord & ~PointerBitMask) == 0 && "Pointer is not sufficiently aligned"); intptr_t FlagWord = static_cast(FlagVal); Value = PtrWord | (FlagWord << BitPosition); } PointerTy const *getAddrOfPointer() const { return const_cast(this)->getAddrOfPointer(); } PointerTy *getAddrOfPointer() { assert(Value == reinterpret_cast(getPointer()) && "Can only return the address if IntBits is cleared and " "PtrTraits doesn't change the pointer"); return reinterpret_cast(&Value); } /// Get the raw pointer value for the underlying pointer /// including its flag value. void *getOpaqueValue() const { return reinterpret_cast(Value); } void setFromOpaqueValue(void *Val) { Value = reinterpret_cast(Val); } static FlaggedPointer getFromOpaqueValue(const void *V) { FlaggedPointer P; P.setFromOpaqueValue(const_cast(V)); return P; } bool operator==(const FlaggedPointer &RHS) const { return Value == RHS.Value; } bool operator!=(const FlaggedPointer &RHS) const { return Value != RHS.Value; } bool operator<(const FlaggedPointer &RHS) const { return Value < RHS.Value; } bool operator>(const FlaggedPointer &RHS) const { return Value > RHS.Value; } bool operator<=(const FlaggedPointer &RHS) const { return Value <= RHS.Value; } bool operator>=(const FlaggedPointer &RHS) const { return Value >= RHS.Value; } }; } // end namespace swift // Teach SmallPtrSet that FlaggedPointer is "basically a pointer". template struct llvm::PointerLikeTypeTraits< swift::FlaggedPointer> { public: static inline void * getAsVoidPointer(const swift::FlaggedPointer &P) { return P.getOpaqueValue(); } static inline swift::FlaggedPointer getFromVoidPointer(void *P) { return swift::FlaggedPointer::getFromOpaqueValue(P); } static inline swift::FlaggedPointer getFromVoidPointer(const void *P) { return swift::FlaggedPointer::getFromOpaqueValue(P); } enum { NumLowBitsAvailable = (BitPosition >= PtrTraits::NumLowBitsAvailable) ? PtrTraits::NumLowBitsAvailable : (std::min(int(BitPosition + 1), int(PtrTraits::NumLowBitsAvailable)) - 1) }; }; #endif // SWIFT_BASIC_FLAGGEDPOINTER_H