| // 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_ZONE_COMPRESSION_H_ |
| #define V8_ZONE_ZONE_COMPRESSION_H_ |
| |
| #include "src/base/bits.h" |
| #include "src/common/globals.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // This struct provides untyped implementation of zone compression scheme. |
| // |
| // The compression scheme relies on the following assumptions: |
| // 1) all zones containing compressed pointers are allocated in the same "zone |
| // cage" of kReservationSize size and kReservationAlignment-aligned. |
| // Attempt to compress pointer to an object stored outside of the "cage" |
| // will silently succeed but it will later produce wrong result after |
| // decompression. |
| // 2) compression is just a masking away bits above kReservationAlignment. |
| // 3) nullptr is compressed to 0, thus there must be no valid objects allocated |
| // at the beginning of the "zone cage". Ideally, the first page of the cage |
| // should be unmapped in order to catch attempts to use decompressed nullptr |
| // value earlier. |
| // 4) decompression requires "zone cage" address value, which is computed on |
| // the fly from an arbitrary address pointing somewhere to the "zone cage". |
| // 5) decompression requires special casing for nullptr. |
| struct ZoneCompression { |
| static const size_t kReservationSize = size_t{2} * GB; |
| static const size_t kReservationAlignment = |
| COMPRESS_ZONES_BOOL ? size_t{4} * GB : 1; |
| |
| static_assert(base::bits::IsPowerOfTwo(kReservationAlignment), |
| "Bad zone alignment"); |
| |
| static const size_t kOffsetMask = kReservationAlignment - 1; |
| |
| inline static Address base_of(const void* zone_pointer) { |
| return reinterpret_cast<Address>(zone_pointer) & ~kOffsetMask; |
| } |
| |
| inline static bool CheckSameBase(const void* p1, const void* p2) { |
| if (p1 == nullptr || p2 == nullptr) return true; |
| CHECK_EQ(base_of(p1), base_of(p2)); |
| return true; |
| } |
| |
| inline static uint32_t Compress(const void* value) { |
| Address raw_value = reinterpret_cast<Address>(value); |
| uint32_t compressed_value = static_cast<uint32_t>(raw_value & kOffsetMask); |
| DCHECK_IMPLIES(compressed_value == 0, value == nullptr); |
| DCHECK_LT(compressed_value, kReservationSize); |
| return compressed_value; |
| } |
| |
| inline static Address Decompress(const void* zone_pointer, |
| uint32_t compressed_value) { |
| if (compressed_value == 0) return kNullAddress; |
| return base_of(zone_pointer) + compressed_value; |
| } |
| }; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_ZONE_ZONE_COMPRESSION_H_ |