Commit 8b57bdba authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

Reland "[zone-compr] Introduce ZoneTypeTraits and ZoneCompression"

This is a reland of 13141c8a

... with a fix for an UB issue of passing null pointers to memcpy()
when size is zero.

TBR=leszeks@chromium.org

Original change's description:
> [zone-compr] Introduce ZoneTypeTraits and ZoneCompression
>
> Also move zone compression flags to src/common/globals.h.
>
> Bug: v8:9923
> Change-Id: Id0a77720e735e2669a1e5eef48e1b4866ad99480
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2324255
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Commit-Queue: Igor Sheludko <ishell@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#69160}

Bug: v8:9923
Change-Id: I2245b81516c39ccea262c282c659ef601af57abf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2332165
Commit-Queue: Igor Sheludko (OOO Aug 3-17) <ishell@chromium.org>
Reviewed-by: 's avatarIgor Sheludko (OOO Aug 3-17) <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69166}
parent 8a002278
......@@ -3307,14 +3307,15 @@ v8_source_set("v8_base_without_compiler") {
"src/zone/type-stats.h",
"src/zone/zone-allocator.h",
"src/zone/zone-chunk-list.h",
"src/zone/zone-compression.h",
"src/zone/zone-containers.h",
"src/zone/zone-fwd.h",
"src/zone/zone-handle-set.h",
"src/zone/zone-hashmap.h",
"src/zone/zone-list-inl.h",
"src/zone/zone-list.h",
"src/zone/zone-segment.cc",
"src/zone/zone-segment.h",
"src/zone/zone-type-traits.h",
"src/zone/zone-utils.h",
"src/zone/zone.cc",
"src/zone/zone.h",
......
......@@ -243,6 +243,16 @@ constexpr size_t kReservedCodeRangePages = 0;
STATIC_ASSERT(kSystemPointerSize == (1 << kSystemPointerSizeLog2));
#ifdef V8_COMPRESS_ZONES
#define COMPRESS_ZONES_BOOL true
#else
#define COMPRESS_ZONES_BOOL false
#endif // V8_COMPRESS_ZONES
// The flag controls whether zones pointer compression should be enabled for
// TurboFan graphs or not.
static constexpr bool kCompressGraphZone = COMPRESS_ZONES_BOOL;
#ifdef V8_COMPRESS_POINTERS
static_assert(
kSystemPointerSize == kInt64Size,
......
......@@ -7,7 +7,7 @@
#include "src/base/macros.h"
#include "src/base/optional.h"
#include "src/zone/zone-fwd.h"
#include "src/zone/zone-type-traits.h"
namespace v8 {
namespace internal {
......
......@@ -10,28 +10,33 @@
#include "src/base/logging.h"
#include "src/base/macros.h"
#include "src/utils/allocation.h"
#include "src/zone/zone-fwd.h"
#include "src/zone/zone-compression.h"
#include "src/zone/zone-segment.h"
namespace v8 {
namespace internal {
// These definitions are here in order to please the linker, which in debug mode
// sometimes requires static constants to be defined in .cc files.
const size_t ZoneCompression::kReservationSize;
const size_t ZoneCompression::kReservationAlignment;
namespace {
static constexpr size_t kZonePageSize = 256 * KB;
VirtualMemory ReserveAddressSpace(v8::PageAllocator* platform_allocator) {
DCHECK(
IsAligned(kZoneReservationSize, platform_allocator->AllocatePageSize()));
DCHECK(IsAligned(ZoneCompression::kReservationSize,
platform_allocator->AllocatePageSize()));
void* hint = reinterpret_cast<void*>(RoundDown(
reinterpret_cast<uintptr_t>(platform_allocator->GetRandomMmapAddr()),
kZoneReservationAlignment));
ZoneCompression::kReservationAlignment));
VirtualMemory memory(platform_allocator, kZoneReservationSize, hint,
kZoneReservationAlignment);
VirtualMemory memory(platform_allocator, ZoneCompression::kReservationSize,
hint, ZoneCompression::kReservationAlignment);
if (memory.IsReserved()) {
CHECK(IsAligned(memory.address(), kZoneReservationAlignment));
CHECK(IsAligned(memory.address(), ZoneCompression::kReservationAlignment));
return memory;
}
......@@ -43,10 +48,11 @@ VirtualMemory ReserveAddressSpace(v8::PageAllocator* platform_allocator) {
std::unique_ptr<v8::base::BoundedPageAllocator> CreateBoundedAllocator(
v8::PageAllocator* platform_allocator, Address reservation_start) {
DCHECK(reservation_start);
CHECK(reservation_start);
CHECK(IsAligned(reservation_start, ZoneCompression::kReservationAlignment));
auto allocator = std::make_unique<v8::base::BoundedPageAllocator>(
platform_allocator, reservation_start, kZoneReservationSize,
platform_allocator, reservation_start, ZoneCompression::kReservationSize,
kZonePageSize);
// Exclude first page from allocation to ensure that accesses through
......
......@@ -40,10 +40,20 @@ class ZoneAllocator {
// ZoneVector and friends or for ParallelMove.
ZoneAllocator() : ZoneAllocator(nullptr) { UNREACHABLE(); }
#endif
explicit ZoneAllocator(Zone* zone) : zone_(zone) {}
explicit ZoneAllocator(Zone* zone) : zone_(zone) {
// If we are going to allocate compressed pointers in the zone it must
// support compression.
DCHECK_IMPLIES(is_compressed_pointer<T>::value,
zone_->supports_compression());
}
template <typename U>
ZoneAllocator(const ZoneAllocator<U>& other) V8_NOEXCEPT
: ZoneAllocator<T>(other.zone_) {}
: ZoneAllocator<T>(other.zone_) {
// If we are going to allocate compressed pointers in the zone it must
// support compression.
DCHECK_IMPLIES(is_compressed_pointer<T>::value,
zone_->supports_compression());
}
template <typename U>
friend class ZoneAllocator;
......
// 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_
// 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_FWD_H_
#define V8_ZONE_ZONE_FWD_H_
#include "src/common/globals.h"
namespace v8 {
namespace internal {
//
// This header contains forward declarations for Zone-related objects and
// containers.
//
class Zone;
template <typename T>
class ZoneList;
// ZonePtrList is a ZoneList of pointers to ZoneObjects allocated in the same
// zone as the list object.
template <typename T>
using ZonePtrList = ZoneList<T*>;
#ifdef V8_COMPRESS_ZONES
static_assert(kSystemPointerSize == 8,
"Zone compression requires 64-bit architectures");
#define COMPRESS_ZONES_BOOL true
constexpr size_t kZoneReservationSize = static_cast<size_t>(2) * GB;
constexpr size_t kZoneReservationAlignment = static_cast<size_t>(4) * GB;
#else // V8_COMPRESS_ZONES
#define COMPRESS_ZONES_BOOL false
// These constants must not be used when zone compression is not enabled.
constexpr size_t kZoneReservationSize = 1;
constexpr size_t kZoneReservationAlignment = 1;
#endif // V8_COMPRESS_ZONES
// The flags controlling whether zones that will be used for allocating
// TurboFan graphs should be compressed or not.
static constexpr bool kCompressGraphZone = COMPRESS_ZONES_BOOL;
} // namespace internal
} // namespace v8
#endif // V8_ZONE_ZONE_FWD_H_
......@@ -29,10 +29,13 @@ void ZoneList<T>::AddAll(const ZoneList<T>& other, Zone* zone) {
template <typename T>
void ZoneList<T>::AddAll(const Vector<const T>& other, Zone* zone) {
int result_length = length_ + other.length();
int length = other.length();
if (length == 0) return;
int result_length = length_ + length;
if (capacity_ < result_length) Resize(result_length, zone);
if (std::is_fundamental<T>()) {
memcpy(&data_[length_], other.begin(), sizeof(T) * other.length());
if (std::is_trivially_copyable<T>::value) {
memcpy(&data_[length_], other.begin(), sizeof(T) * length);
} else {
std::copy(other.begin(), other.end(), &data_[length_]);
}
......@@ -64,7 +67,7 @@ void ZoneList<T>::Resize(int new_capacity, Zone* zone) {
DCHECK_LE(length_, new_capacity);
T* new_data = zone->NewArray<T>(new_capacity);
if (length_ > 0) {
if (std::is_fundamental<T>()) {
if (std::is_trivially_copyable<T>::value) {
MemCopy(new_data, data_, length_ * sizeof(T));
} else {
std::copy(&data_[0], &data_[length_], &new_data[0]);
......
......@@ -6,7 +6,6 @@
#define V8_ZONE_ZONE_LIST_H_
#include "src/base/logging.h"
#include "src/zone/zone-fwd.h"
#include "src/zone/zone.h"
namespace v8 {
......
// 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_TYPE_TRAITS_H_
#define V8_ZONE_ZONE_TYPE_TRAITS_H_
#include "src/common/globals.h"
namespace v8 {
namespace internal {
template <typename T>
class ZoneList;
// ZonePtrList is a ZoneList of pointers to ZoneObjects allocated in the same
// zone as the list object.
template <typename T>
using ZonePtrList = ZoneList<T*>;
template <typename T>
using FullZonePtr = T*;
template <typename T>
class CompressedZonePtr;
//
// ZoneTypeTraits provides type aliases for compressed or full pointer
// dependent types based on a static flag. It helps organizing fine-grained
// control over which parts of the code base should use compressed zone
// pointers.
// For example:
// using ZoneNodePtr = typename ZoneTypeTraits<kCompressGraphZone>::Ptr<Node>;
//
// or
// template <typename T>
// using AstZonePtr = typename ZoneTypeTraits<kCompressAstZone>::Ptr<T>;
//
template <bool kEnableCompression>
struct ZoneTypeTraits;
template <>
struct ZoneTypeTraits<false> {
template <typename T>
using Ptr = FullZonePtr<T>;
};
template <>
struct ZoneTypeTraits<true> {
// TODO(ishell): use CompressedZonePtr<T> here
template <typename T>
using Ptr = FullZonePtr<T>;
};
// This requirement is necessary for being able to use memcopy in containers
// of zone pointers.
static_assert(
std::is_trivially_copyable<
ZoneTypeTraits<COMPRESS_ZONES_BOOL>::Ptr<int>>::value,
"ZoneTypeTraits<COMPRESS_ZONES_BOOL>::Ptr<T> must be trivially copyable");
//
// is_compressed_pointer<T> predicate can be used for checking if T is a
// compressed pointer.
//
template <typename>
struct is_compressed_pointer : std::false_type {};
template <typename T>
struct is_compressed_pointer<CompressedZonePtr<T>> : std::true_type {};
template <typename T>
struct is_compressed_pointer<const CompressedZonePtr<T>> : std::true_type {};
} // namespace internal
} // namespace v8
#endif // V8_ZONE_ZONE_TYPE_TRAITS_H_
......@@ -20,7 +20,7 @@ Vector<T> CloneVector(Zone* zone, const Vector<const T>& other) {
if (length == 0) return Vector<T>();
T* data = zone->NewArray<T>(length);
if (std::is_fundamental<T>()) {
if (std::is_trivially_copyable<T>::value) {
MemCopy(data, other.data(), length * sizeof(T));
} else {
std::copy(other.begin(), other.end(), data);
......
......@@ -9,10 +9,11 @@
#include "src/base/logging.h"
#include "src/common/globals.h"
#include "src/utils/utils.h"
#include "src/zone/accounting-allocator.h"
#include "src/zone/type-stats.h"
#include "src/zone/zone-fwd.h"
#include "src/zone/zone-segment.h"
#include "src/zone/zone-type-traits.h"
#ifndef ZONE_NAME
#define ZONE_NAME __func__
......@@ -116,6 +117,7 @@ class V8_EXPORT_PRIVATE Zone final {
// distinguishable between each other.
template <typename T, typename TypeTag = T[]>
T* NewArray(size_t length) {
DCHECK_IMPLIES(is_compressed_pointer<T>::value, supports_compression());
DCHECK_LT(length, std::numeric_limits<size_t>::max() / sizeof(T));
return static_cast<T*>(Allocate<TypeTag>(length * sizeof(T)));
}
......
......@@ -10,7 +10,6 @@
#include "src/compiler/pipeline.h"
#include "src/compiler/raw-machine-assembler.h"
#include "src/execution/simulator.h"
#include "src/zone/zone-fwd.h"
#include "test/cctest/cctest.h"
#include "test/cctest/compiler/call-tester.h"
......
......@@ -14,7 +14,6 @@
#include "src/compiler/schedule.h"
#include "src/compiler/scheduler.h"
#include "src/compiler/verifier.h"
#include "src/zone/zone-fwd.h"
#include "test/cctest/cctest.h"
namespace v8 {
......
......@@ -5,7 +5,6 @@
#include "src/compiler/backend/instruction-scheduler.h"
#include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/backend/instruction.h"
#include "src/zone/zone-fwd.h"
#include "test/cctest/cctest.h"
namespace v8 {
......
......@@ -7,7 +7,6 @@
#include "src/compiler/graph.h"
#include "src/compiler/node.h"
#include "src/compiler/operator.h"
#include "src/zone/zone-fwd.h"
#include "test/cctest/cctest.h"
namespace v8 {
......
......@@ -6,7 +6,6 @@
#define V8_UNITTESTS_CODE_STUB_ASSEMBLER_UNITTEST_H_
#include "src/codegen/code-stub-assembler.h"
#include "src/zone/zone-fwd.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock-support.h"
......
......@@ -8,7 +8,6 @@
#include "src/compiler/node-properties.h"
#include "src/heap/factory.h"
#include "src/objects/objects-inl.h" // TODO(everyone): Make typer.h IWYU compliant.
#include "src/zone/zone-fwd.h"
#include "test/unittests/compiler/node-test-utils.h"
namespace v8 {
......
......@@ -5,7 +5,6 @@
#include "src/compiler/schedule.h"
#include "src/compiler/node.h"
#include "src/zone/zone-fwd.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h"
......
......@@ -9,7 +9,6 @@
#include "src/compiler/graph.h"
#include "src/compiler/node.h"
#include "src/compiler/operator.h"
#include "src/zone/zone-fwd.h"
#include "test/unittests/test-utils.h"
namespace v8 {
......
......@@ -15,6 +15,7 @@
#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-opcodes-inl.h"
#include "src/zone/zone.h"
#include "test/common/wasm/flag-utils.h"
#include "test/common/wasm/test-signatures.h"
#include "test/common/wasm/wasm-macro-gen.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment