1// Copyright 2020 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
6#define INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
7
8#include <array>
9#include <cstddef>
10#include <cstdint>
11
12#include "cppgc/internal/api-constants.h"
13#include "cppgc/internal/caged-heap.h"
14#include "cppgc/internal/logging.h"
15#include "cppgc/platform.h"
16#include "v8config.h"  // NOLINT(build/include_directory)
17
18#if __cpp_lib_bitopts
19#include <bit>
20#endif  // __cpp_lib_bitopts
21
22#if defined(CPPGC_CAGED_HEAP)
23
24namespace cppgc {
25namespace internal {
26
27class HeapBase;
28class HeapBaseHandle;
29
30#if defined(CPPGC_YOUNG_GENERATION)
31
32// AgeTable is the bytemap needed for the fast generation check in the write
33// barrier. AgeTable contains entries that correspond to 4096 bytes memory
34// regions (cards). Each entry in the table represents generation of the objects
35// that reside on the corresponding card (young, old or mixed).
36class V8_EXPORT AgeTable final {
37  static constexpr size_t kRequiredSize = 1 * api_constants::kMB;
38  static constexpr size_t kAllocationGranularity =
39      api_constants::kAllocationGranularity;
40
41 public:
42  // Represents age of the objects living on a single card.
43  enum class Age : uint8_t { kOld, kYoung, kMixed };
44  // When setting age for a range, consider or ignore ages of the adjacent
45  // cards.
46  enum class AdjacentCardsPolicy : uint8_t { kConsider, kIgnore };
47
48  static constexpr size_t kCardSizeInBytes =
49      api_constants::kCagedHeapReservationSize / kRequiredSize;
50
51  void SetAge(uintptr_t cage_offset, Age age) {
52    table_[card(cage_offset)] = age;
53  }
54
55  V8_INLINE Age GetAge(uintptr_t cage_offset) const {
56    return table_[card(cage_offset)];
57  }
58
59  void SetAgeForRange(uintptr_t cage_offset_begin, uintptr_t cage_offset_end,
60                      Age age, AdjacentCardsPolicy adjacent_cards_policy);
61
62  Age GetAgeForRange(uintptr_t cage_offset_begin,
63                     uintptr_t cage_offset_end) const;
64
65  void ResetForTesting();
66
67 private:
68  V8_INLINE size_t card(uintptr_t offset) const {
69    constexpr size_t kGranularityBits =
70#if __cpp_lib_bitopts
71        std::countr_zero(static_cast<uint32_t>(kCardSizeInBytes));
72#elif V8_HAS_BUILTIN_CTZ
73        __builtin_ctz(static_cast<uint32_t>(kCardSizeInBytes));
74#else   //! V8_HAS_BUILTIN_CTZ
75        // Hardcode and check with assert.
76#if defined(CPPGC_2GB_CAGE)
77        11;
78#else   // !defined(CPPGC_2GB_CAGE)
79        12;
80#endif  // !defined(CPPGC_2GB_CAGE)
81#endif  // !V8_HAS_BUILTIN_CTZ
82    static_assert((1 << kGranularityBits) == kCardSizeInBytes);
83    const size_t entry = offset >> kGranularityBits;
84    CPPGC_DCHECK(table_.size() > entry);
85    return entry;
86  }
87
88  std::array<Age, kRequiredSize> table_;
89};
90
91static_assert(sizeof(AgeTable) == 1 * api_constants::kMB,
92              "Size of AgeTable is 1MB");
93
94#endif  // CPPGC_YOUNG_GENERATION
95
96struct CagedHeapLocalData final {
97  V8_INLINE static CagedHeapLocalData& Get() {
98    return *reinterpret_cast<CagedHeapLocalData*>(CagedHeapBase::GetBase());
99  }
100
101#if defined(CPPGC_YOUNG_GENERATION)
102  AgeTable age_table;
103#endif
104};
105
106}  // namespace internal
107}  // namespace cppgc
108
109#endif  // defined(CPPGC_CAGED_HEAP)
110
111#endif  // INCLUDE_CPPGC_INTERNAL_CAGED_HEAP_LOCAL_DATA_H_
112