blob: 4932dabca3f3e4918cf352c171e5dd603c0fb4e0 [file] [log] [blame]
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_ZONE_COMPRESSED_ZONE_PTR_H_
#define V8_ZONE_COMPRESSED_ZONE_PTR_H_
#include <type_traits>
#include "src/base/logging.h"
#include "src/common/globals.h"
#include "src/zone/zone-compression.h"
namespace v8 {
namespace internal {
//
// Compressed pointer to T using aligned-base-relative addressing compression.
//
// Note that the CompressedZonePtr<T> is implicitly convertible to T*.
// Such an approach provides the benefit of almost seamless migration of a code
// using full pointers to compressed pointers.
// However, using CompressedZonePtr<T> in containers is not allowed yet.
//
// It's not recommended to use this class directly, use ZoneTypeTraits::Ptr<T>
// instead.
template <typename T>
class CompressedZonePtr {
public:
CompressedZonePtr() = default;
explicit CompressedZonePtr(std::nullptr_t) : CompressedZonePtr() {}
explicit CompressedZonePtr(T* value) { *this = value; }
// Move- and copy-constructors are explicitly deleted in order to avoid
// creation of temporary objects which we can't uncompress because they will
// live outside of the zone memory.
CompressedZonePtr(const CompressedZonePtr& other) V8_NOEXCEPT = delete;
CompressedZonePtr(CompressedZonePtr&&) V8_NOEXCEPT = delete;
CompressedZonePtr& operator=(const CompressedZonePtr& other) V8_NOEXCEPT {
DCHECK(ZoneCompression::CheckSameBase(this, &other));
compressed_value_ = other.compressed_value_;
return *this;
}
CompressedZonePtr& operator=(CompressedZonePtr&& other) V8_NOEXCEPT = delete;
CompressedZonePtr& operator=(T* value) {
compressed_value_ = ZoneCompression::Compress(value);
DCHECK_EQ(value, Decompress());
return *this;
}
bool operator==(std::nullptr_t) const { return compressed_value_ == 0; }
bool operator!=(std::nullptr_t) const { return compressed_value_ != 0; }
// The equality comparisons assume that both operands point to objects
// allocated by the same allocator supporting pointer compression, therefore
// it's enough to compare compressed values.
bool operator==(const CompressedZonePtr& other) const {
return compressed_value_ == other.compressed_value_;
}
bool operator!=(const CompressedZonePtr& other) const {
return !(*this == other);
}
bool operator==(T* other) const {
return compressed_value_ == ZoneCompression::Compress(other);
}
bool operator!=(T* other) const { return !(*this == other); }
T& operator*() const { return *Decompress(); }
T* operator->() const { return Decompress(); }
operator T*() const { return Decompress(); }
operator bool() const { return compressed_value_ != 0; }
private:
T* Decompress() const {
return reinterpret_cast<T*>(
ZoneCompression::Decompress(this, compressed_value_));
}
uint32_t compressed_value_ = 0;
};
// This requirement is necessary for being able to use memcopy in containers
// of zone pointers.
// TODO(ishell): Re-enable once compressed pointers are supported in containers.
// static_assert(std::is_trivially_copyable<CompressedZonePtr<int>>::value,
// "CompressedZonePtr must be trivially copyable");
} // namespace internal
} // namespace v8
#endif // V8_ZONE_COMPRESSED_ZONE_PTR_H_