blob: a682aaff8b91ca4a9ccb522269d3d55897ac0103 [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_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_