mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
179 lines
5.7 KiB
C++
179 lines
5.7 KiB
C++
//===--- 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 <cassert>
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/PointerLikeTypeTraits.h"
|
|
|
|
#include "Algorithm.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 <typename PointerTy,
|
|
unsigned BitPosition,
|
|
typename PtrTraits = llvm::PointerLikeTypeTraits<PointerTy>>
|
|
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<void*>(Value & PointerBitMask));
|
|
}
|
|
|
|
void setPointer(PointerTy PtrVal) {
|
|
intptr_t PtrWord = reinterpret_cast<intptr_t>(
|
|
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<intptr_t>(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<intptr_t>(
|
|
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<intptr_t>(
|
|
PtrTraits::getAsVoidPointer(PtrVal));
|
|
assert((PtrWord & ~PointerBitMask) == 0 &&
|
|
"Pointer is not sufficiently aligned");
|
|
intptr_t FlagWord = static_cast<intptr_t>(FlagVal);
|
|
|
|
Value = PtrWord | (FlagWord << BitPosition);
|
|
}
|
|
|
|
PointerTy const *getAddrOfPointer() const {
|
|
return const_cast<FlaggedPointer *>(this)->getAddrOfPointer();
|
|
}
|
|
|
|
PointerTy *getAddrOfPointer() {
|
|
assert(Value == reinterpret_cast<intptr_t>(getPointer()) &&
|
|
"Can only return the address if IntBits is cleared and "
|
|
"PtrTraits doesn't change the pointer");
|
|
return reinterpret_cast<PointerTy *>(&Value);
|
|
}
|
|
|
|
/// Get the raw pointer value for the underlying pointer
|
|
/// including its flag value.
|
|
void *getOpaqueValue() const {
|
|
return reinterpret_cast<void*>(Value);
|
|
}
|
|
|
|
void setFromOpaqueValue(void *Val) {
|
|
Value = reinterpret_cast<intptr_t>(Val);
|
|
}
|
|
|
|
static FlaggedPointer getFromOpaqueValue(const void *V) {
|
|
FlaggedPointer P;
|
|
P.setFromOpaqueValue(const_cast<void *>(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 <typename PointerTy, unsigned BitPosition, typename PtrTraits>
|
|
class llvm::PointerLikeTypeTraits<
|
|
swift::FlaggedPointer<PointerTy, BitPosition, PtrTraits>> {
|
|
public:
|
|
static inline void *
|
|
getAsVoidPointer(const swift::FlaggedPointer<PointerTy, BitPosition> &P) {
|
|
return P.getOpaqueValue();
|
|
}
|
|
static inline swift::FlaggedPointer<PointerTy, BitPosition>
|
|
getFromVoidPointer(void *P) {
|
|
return swift::FlaggedPointer<PointerTy, BitPosition>::getFromOpaqueValue(P);
|
|
}
|
|
static inline swift::FlaggedPointer<PointerTy, BitPosition>
|
|
getFromVoidPointer(const void *P) {
|
|
return swift::FlaggedPointer<PointerTy, BitPosition>::getFromOpaqueValue(P);
|
|
}
|
|
enum {
|
|
NumLowBitsAvailable = (BitPosition >= PtrTraits::NumLowBitsAvailable)
|
|
? PtrTraits::NumLowBitsAvailable
|
|
: (swift::min(int(BitPosition + 1),
|
|
int(PtrTraits::NumLowBitsAvailable)) - 1)
|
|
};
|
|
};
|
|
|
|
#endif // SWIFT_BASIC_FLAGGEDPOINTER_H
|