Coverage Report

Created: 2025-07-04 09:33

/src/node/deps/v8/include/cppgc/internal/write-barrier.h
Line
Count
Source (jump to first uncovered line)
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_WRITE_BARRIER_H_
6
#define INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_
7
8
#include <cstddef>
9
#include <cstdint>
10
11
#include "cppgc/heap-handle.h"
12
#include "cppgc/heap-state.h"
13
#include "cppgc/internal/api-constants.h"
14
#include "cppgc/internal/atomic-entry-flag.h"
15
#include "cppgc/internal/base-page-handle.h"
16
#include "cppgc/internal/member-storage.h"
17
#include "cppgc/platform.h"
18
#include "cppgc/sentinel-pointer.h"
19
#include "cppgc/trace-trait.h"
20
#include "v8config.h"  // NOLINT(build/include_directory)
21
22
#if defined(CPPGC_CAGED_HEAP)
23
#include "cppgc/internal/caged-heap-local-data.h"
24
#include "cppgc/internal/caged-heap.h"
25
#endif
26
27
namespace cppgc {
28
29
class HeapHandle;
30
31
namespace internal {
32
33
#if defined(CPPGC_CAGED_HEAP)
34
class WriteBarrierTypeForCagedHeapPolicy;
35
#else   // !CPPGC_CAGED_HEAP
36
class WriteBarrierTypeForNonCagedHeapPolicy;
37
#endif  // !CPPGC_CAGED_HEAP
38
39
class V8_EXPORT WriteBarrier final {
40
 public:
41
  enum class Type : uint8_t {
42
    kNone,
43
    kMarking,
44
    kGenerational,
45
  };
46
47
  enum class GenerationalBarrierType : uint8_t {
48
    kPreciseSlot,
49
    kPreciseUncompressedSlot,
50
    kImpreciseSlot,
51
  };
52
53
  struct Params {
54
    HeapHandle* heap = nullptr;
55
#if V8_ENABLE_CHECKS
56
    Type type = Type::kNone;
57
#endif  // !V8_ENABLE_CHECKS
58
#if defined(CPPGC_CAGED_HEAP)
59
    uintptr_t slot_offset = 0;
60
    uintptr_t value_offset = 0;
61
#endif  // CPPGC_CAGED_HEAP
62
  };
63
64
  enum class ValueMode {
65
    kValuePresent,
66
    kNoValuePresent,
67
  };
68
69
  // Returns the required write barrier for a given `slot` and `value`.
70
  static V8_INLINE Type GetWriteBarrierType(const void* slot, const void* value,
71
                                            Params& params);
72
  // Returns the required write barrier for a given `slot` and `value`.
73
  template <typename MemberStorage>
74
  static V8_INLINE Type GetWriteBarrierType(const void* slot, MemberStorage,
75
                                            Params& params);
76
  // Returns the required write barrier for a given `slot`.
77
  template <typename HeapHandleCallback>
78
  static V8_INLINE Type GetWriteBarrierType(const void* slot, Params& params,
79
                                            HeapHandleCallback callback);
80
  // Returns the required write barrier for a given  `value`.
81
  static V8_INLINE Type GetWriteBarrierType(const void* value, Params& params);
82
83
#ifdef CPPGC_SLIM_WRITE_BARRIER
84
  // A write barrier that combines `GenerationalBarrier()` and
85
  // `DijkstraMarkingBarrier()`. We only pass a single parameter here to clobber
86
  // as few registers as possible.
87
  template <WriteBarrierSlotType>
88
  static V8_NOINLINE void V8_PRESERVE_MOST
89
  CombinedWriteBarrierSlow(const void* slot);
90
#endif  // CPPGC_SLIM_WRITE_BARRIER
91
92
  static V8_INLINE void DijkstraMarkingBarrier(const Params& params,
93
                                               const void* object);
94
  static V8_INLINE void DijkstraMarkingBarrierRange(
95
      const Params& params, const void* first_element, size_t element_size,
96
      size_t number_of_elements, TraceCallback trace_callback);
97
  static V8_INLINE void SteeleMarkingBarrier(const Params& params,
98
                                             const void* object);
99
#if defined(CPPGC_YOUNG_GENERATION)
100
  template <GenerationalBarrierType>
101
  static V8_INLINE void GenerationalBarrier(const Params& params,
102
                                            const void* slot);
103
#else  // !CPPGC_YOUNG_GENERATION
104
  template <GenerationalBarrierType>
105
  static V8_INLINE void GenerationalBarrier(const Params& params,
106
0
                                            const void* slot){}
107
#endif  // CPPGC_YOUNG_GENERATION
108
109
#if V8_ENABLE_CHECKS
110
  static void CheckParams(Type expected_type, const Params& params);
111
#else   // !V8_ENABLE_CHECKS
112
0
  static void CheckParams(Type expected_type, const Params& params) {}
113
#endif  // !V8_ENABLE_CHECKS
114
115
  // The FlagUpdater class allows cppgc internal to update
116
  // |write_barrier_enabled_|.
117
  class FlagUpdater;
118
0
  static bool IsEnabled() { return write_barrier_enabled_.MightBeEntered(); }
119
120
 private:
121
  WriteBarrier() = delete;
122
123
#if defined(CPPGC_CAGED_HEAP)
124
  using WriteBarrierTypePolicy = WriteBarrierTypeForCagedHeapPolicy;
125
#else   // !CPPGC_CAGED_HEAP
126
  using WriteBarrierTypePolicy = WriteBarrierTypeForNonCagedHeapPolicy;
127
#endif  // !CPPGC_CAGED_HEAP
128
129
  static void DijkstraMarkingBarrierSlow(const void* value);
130
  static void DijkstraMarkingBarrierSlowWithSentinelCheck(const void* value);
131
  static void DijkstraMarkingBarrierRangeSlow(HeapHandle& heap_handle,
132
                                              const void* first_element,
133
                                              size_t element_size,
134
                                              size_t number_of_elements,
135
                                              TraceCallback trace_callback);
136
  static void SteeleMarkingBarrierSlow(const void* value);
137
  static void SteeleMarkingBarrierSlowWithSentinelCheck(const void* value);
138
139
#if defined(CPPGC_YOUNG_GENERATION)
140
  static CagedHeapLocalData& GetLocalData(HeapHandle&);
141
  static void GenerationalBarrierSlow(const CagedHeapLocalData& local_data,
142
                                      const AgeTable& age_table,
143
                                      const void* slot, uintptr_t value_offset,
144
                                      HeapHandle* heap_handle);
145
  static void GenerationalBarrierForUncompressedSlotSlow(
146
      const CagedHeapLocalData& local_data, const AgeTable& age_table,
147
      const void* slot, uintptr_t value_offset, HeapHandle* heap_handle);
148
  static void GenerationalBarrierForSourceObjectSlow(
149
      const CagedHeapLocalData& local_data, const void* object,
150
      HeapHandle* heap_handle);
151
#endif  // CPPGC_YOUNG_GENERATION
152
153
  static AtomicEntryFlag write_barrier_enabled_;
154
};
155
156
template <WriteBarrier::Type type>
157
0
V8_INLINE WriteBarrier::Type SetAndReturnType(WriteBarrier::Params& params) {
158
0
  if constexpr (type == WriteBarrier::Type::kNone)
159
0
    return WriteBarrier::Type::kNone;
160
0
#if V8_ENABLE_CHECKS
161
0
  params.type = type;
162
0
#endif  // !V8_ENABLE_CHECKS
163
0
  return type;
164
0
}
Unexecuted instantiation: cppgc::internal::WriteBarrier::Type cppgc::internal::SetAndReturnType<(cppgc::internal::WriteBarrier::Type)0>(cppgc::internal::WriteBarrier::Params&)
Unexecuted instantiation: cppgc::internal::WriteBarrier::Type cppgc::internal::SetAndReturnType<(cppgc::internal::WriteBarrier::Type)1>(cppgc::internal::WriteBarrier::Params&)
165
166
#if defined(CPPGC_CAGED_HEAP)
167
class V8_EXPORT WriteBarrierTypeForCagedHeapPolicy final {
168
 public:
169
  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
170
  static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
171
                                          WriteBarrier::Params& params,
172
                                          HeapHandleCallback callback) {
173
    return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
174
  }
175
176
  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback,
177
            typename MemberStorage>
178
  static V8_INLINE WriteBarrier::Type Get(const void* slot, MemberStorage value,
179
                                          WriteBarrier::Params& params,
180
                                          HeapHandleCallback callback) {
181
    return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
182
  }
183
184
  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
185
  static V8_INLINE WriteBarrier::Type Get(const void* value,
186
                                          WriteBarrier::Params& params,
187
                                          HeapHandleCallback callback) {
188
    return GetNoSlot(value, params, callback);
189
  }
190
191
 private:
192
  WriteBarrierTypeForCagedHeapPolicy() = delete;
193
194
  template <typename HeapHandleCallback>
195
  static V8_INLINE WriteBarrier::Type GetNoSlot(const void* value,
196
                                                WriteBarrier::Params& params,
197
                                                HeapHandleCallback) {
198
    const bool within_cage = CagedHeapBase::IsWithinCage(value);
199
    if (!within_cage) return WriteBarrier::Type::kNone;
200
201
    // We know that |value| points either within the normal page or to the
202
    // beginning of large-page, so extract the page header by bitmasking.
203
    BasePageHandle* page =
204
        BasePageHandle::FromPayload(const_cast<void*>(value));
205
206
    HeapHandle& heap_handle = page->heap_handle();
207
    if (V8_UNLIKELY(heap_handle.is_incremental_marking_in_progress())) {
208
      return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
209
    }
210
211
    return SetAndReturnType<WriteBarrier::Type::kNone>(params);
212
  }
213
214
  template <WriteBarrier::ValueMode value_mode>
215
  struct ValueModeDispatch;
216
};
217
218
template <>
219
struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
220
    WriteBarrier::ValueMode::kValuePresent> {
221
  template <typename HeapHandleCallback, typename MemberStorage>
222
  static V8_INLINE WriteBarrier::Type Get(const void* slot,
223
                                          MemberStorage storage,
224
                                          WriteBarrier::Params& params,
225
                                          HeapHandleCallback) {
226
    if (V8_LIKELY(!WriteBarrier::IsEnabled()))
227
      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
228
229
    return BarrierEnabledGet(slot, storage.Load(), params);
230
  }
231
232
  template <typename HeapHandleCallback>
233
  static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
234
                                          WriteBarrier::Params& params,
235
                                          HeapHandleCallback) {
236
    if (V8_LIKELY(!WriteBarrier::IsEnabled()))
237
      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
238
239
    return BarrierEnabledGet(slot, value, params);
240
  }
241
242
 private:
243
  static V8_INLINE WriteBarrier::Type BarrierEnabledGet(
244
      const void* slot, const void* value, WriteBarrier::Params& params) {
245
    const bool within_cage = CagedHeapBase::AreWithinCage(slot, value);
246
    if (!within_cage) return WriteBarrier::Type::kNone;
247
248
    // We know that |value| points either within the normal page or to the
249
    // beginning of large-page, so extract the page header by bitmasking.
250
    BasePageHandle* page =
251
        BasePageHandle::FromPayload(const_cast<void*>(value));
252
253
    HeapHandle& heap_handle = page->heap_handle();
254
    if (V8_LIKELY(!heap_handle.is_incremental_marking_in_progress())) {
255
#if defined(CPPGC_YOUNG_GENERATION)
256
      if (!heap_handle.is_young_generation_enabled())
257
        return WriteBarrier::Type::kNone;
258
      params.heap = &heap_handle;
259
      params.slot_offset = CagedHeapBase::OffsetFromAddress(slot);
260
      params.value_offset = CagedHeapBase::OffsetFromAddress(value);
261
      return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
262
#else   // !CPPGC_YOUNG_GENERATION
263
      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
264
#endif  // !CPPGC_YOUNG_GENERATION
265
    }
266
267
    // Use marking barrier.
268
    params.heap = &heap_handle;
269
    return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
270
  }
271
};
272
273
template <>
274
struct WriteBarrierTypeForCagedHeapPolicy::ValueModeDispatch<
275
    WriteBarrier::ValueMode::kNoValuePresent> {
276
  template <typename HeapHandleCallback>
277
  static V8_INLINE WriteBarrier::Type Get(const void* slot, const void*,
278
                                          WriteBarrier::Params& params,
279
                                          HeapHandleCallback callback) {
280
    if (V8_LIKELY(!WriteBarrier::IsEnabled()))
281
      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
282
283
    HeapHandle& handle = callback();
284
#if defined(CPPGC_YOUNG_GENERATION)
285
    if (V8_LIKELY(!handle.is_incremental_marking_in_progress())) {
286
      if (!handle.is_young_generation_enabled()) {
287
        return WriteBarrier::Type::kNone;
288
      }
289
      params.heap = &handle;
290
      // Check if slot is on stack.
291
      if (V8_UNLIKELY(!CagedHeapBase::IsWithinCage(slot))) {
292
        return SetAndReturnType<WriteBarrier::Type::kNone>(params);
293
      }
294
      params.slot_offset = CagedHeapBase::OffsetFromAddress(slot);
295
      return SetAndReturnType<WriteBarrier::Type::kGenerational>(params);
296
    }
297
#else   // !defined(CPPGC_YOUNG_GENERATION)
298
    if (V8_UNLIKELY(!handle.is_incremental_marking_in_progress())) {
299
      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
300
    }
301
#endif  // !defined(CPPGC_YOUNG_GENERATION)
302
    params.heap = &handle;
303
    return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
304
  }
305
};
306
307
#endif  // CPPGC_CAGED_HEAP
308
309
class V8_EXPORT WriteBarrierTypeForNonCagedHeapPolicy final {
310
 public:
311
  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
312
  static V8_INLINE WriteBarrier::Type Get(const void* slot, const void* value,
313
                                          WriteBarrier::Params& params,
314
0
                                          HeapHandleCallback callback) {
315
0
    return ValueModeDispatch<value_mode>::Get(slot, value, params, callback);
316
0
  }
Unexecuted instantiation: cppgc::internal::WriteBarrier::Type cppgc::internal::WriteBarrierTypeForNonCagedHeapPolicy::Get<(cppgc::internal::WriteBarrier::ValueMode)0, cppgc::internal::WriteBarrier::GetWriteBarrierType(void const*, void const*, cppgc::internal::WriteBarrier::Params&)::{lambda()#1}>(void const*, void const*, cppgc::internal::WriteBarrier::Params&, cppgc::internal::WriteBarrier::GetWriteBarrierType(void const*, void const*, cppgc::internal::WriteBarrier::Params&)::{lambda()#1})
Unexecuted instantiation: cppgc::internal::WriteBarrier::Type cppgc::internal::WriteBarrierTypeForNonCagedHeapPolicy::Get<(cppgc::internal::WriteBarrier::ValueMode)0, cppgc::internal::WriteBarrier::GetWriteBarrierType(void const*, cppgc::internal::WriteBarrier::Params&)::{lambda()#1}>(void const*, void const*, cppgc::internal::WriteBarrier::Params&, cppgc::internal::WriteBarrier::GetWriteBarrierType(void const*, cppgc::internal::WriteBarrier::Params&)::{lambda()#1})
317
318
  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
319
  static V8_INLINE WriteBarrier::Type Get(const void* slot, RawPointer value,
320
                                          WriteBarrier::Params& params,
321
                                          HeapHandleCallback callback) {
322
    return ValueModeDispatch<value_mode>::Get(slot, value.Load(), params,
323
                                              callback);
324
  }
325
326
  template <WriteBarrier::ValueMode value_mode, typename HeapHandleCallback>
327
  static V8_INLINE WriteBarrier::Type Get(const void* value,
328
                                          WriteBarrier::Params& params,
329
0
                                          HeapHandleCallback callback) {
330
0
    // The slot will never be used in `Get()` below.
331
0
    return Get<WriteBarrier::ValueMode::kValuePresent>(nullptr, value, params,
332
0
                                                       callback);
333
0
  }
334
335
 private:
336
  template <WriteBarrier::ValueMode value_mode>
337
  struct ValueModeDispatch;
338
339
  WriteBarrierTypeForNonCagedHeapPolicy() = delete;
340
};
341
342
template <>
343
struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
344
    WriteBarrier::ValueMode::kValuePresent> {
345
  template <typename HeapHandleCallback>
346
  static V8_INLINE WriteBarrier::Type Get(const void*, const void* object,
347
                                          WriteBarrier::Params& params,
348
0
                                          HeapHandleCallback callback) {
349
0
    // The following check covers nullptr as well as sentinel pointer.
350
0
    if (object <= static_cast<void*>(kSentinelPointer)) {
351
0
      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
352
0
    }
353
0
    if (V8_LIKELY(!WriteBarrier::IsEnabled())) {
354
0
      return SetAndReturnType<WriteBarrier::Type::kNone>(params);
355
0
    }
356
0
    // We know that |object| is within the normal page or in the beginning of a
357
0
    // large page, so extract the page header by bitmasking.
358
0
    BasePageHandle* page =
359
0
        BasePageHandle::FromPayload(const_cast<void*>(object));
360
0
361
0
    HeapHandle& heap_handle = page->heap_handle();
362
0
    if (V8_LIKELY(heap_handle.is_incremental_marking_in_progress())) {
363
0
      return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
364
0
    }
365
0
    return SetAndReturnType<WriteBarrier::Type::kNone>(params);
366
0
  }
Unexecuted instantiation: cppgc::internal::WriteBarrier::Type cppgc::internal::WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<(cppgc::internal::WriteBarrier::ValueMode)0>::Get<cppgc::internal::WriteBarrier::GetWriteBarrierType(void const*, void const*, cppgc::internal::WriteBarrier::Params&)::{lambda()#1}>(void const*, void const*, cppgc::internal::WriteBarrier::Params&, cppgc::internal::WriteBarrier::GetWriteBarrierType(void const*, void const*, cppgc::internal::WriteBarrier::Params&)::{lambda()#1})
Unexecuted instantiation: cppgc::internal::WriteBarrier::Type cppgc::internal::WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<(cppgc::internal::WriteBarrier::ValueMode)0>::Get<cppgc::internal::WriteBarrier::GetWriteBarrierType(void const*, cppgc::internal::WriteBarrier::Params&)::{lambda()#1}>(void const*, void const*, cppgc::internal::WriteBarrier::Params&, cppgc::internal::WriteBarrier::GetWriteBarrierType(void const*, cppgc::internal::WriteBarrier::Params&)::{lambda()#1})
367
};
368
369
template <>
370
struct WriteBarrierTypeForNonCagedHeapPolicy::ValueModeDispatch<
371
    WriteBarrier::ValueMode::kNoValuePresent> {
372
  template <typename HeapHandleCallback>
373
  static V8_INLINE WriteBarrier::Type Get(const void*, const void*,
374
                                          WriteBarrier::Params& params,
375
                                          HeapHandleCallback callback) {
376
    if (V8_UNLIKELY(WriteBarrier::IsEnabled())) {
377
      HeapHandle& handle = callback();
378
      if (V8_LIKELY(handle.is_incremental_marking_in_progress())) {
379
        params.heap = &handle;
380
        return SetAndReturnType<WriteBarrier::Type::kMarking>(params);
381
      }
382
    }
383
    return WriteBarrier::Type::kNone;
384
  }
385
};
386
387
// static
388
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
389
0
    const void* slot, const void* value, WriteBarrier::Params& params) {
390
0
  return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(slot, value,
391
0
                                                               params, []() {});
392
0
}
393
394
// static
395
template <typename MemberStorage>
396
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
397
    const void* slot, MemberStorage value, WriteBarrier::Params& params) {
398
  return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(slot, value,
399
                                                               params, []() {});
400
}
401
402
// static
403
template <typename HeapHandleCallback>
404
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
405
    const void* slot, WriteBarrier::Params& params,
406
    HeapHandleCallback callback) {
407
  return WriteBarrierTypePolicy::Get<ValueMode::kNoValuePresent>(
408
      slot, nullptr, params, callback);
409
}
410
411
// static
412
WriteBarrier::Type WriteBarrier::GetWriteBarrierType(
413
0
    const void* value, WriteBarrier::Params& params) {
414
0
  return WriteBarrierTypePolicy::Get<ValueMode::kValuePresent>(value, params,
415
0
                                                               []() {});
416
0
}
417
418
// static
419
void WriteBarrier::DijkstraMarkingBarrier(const Params& params,
420
0
                                          const void* object) {
421
0
  CheckParams(Type::kMarking, params);
422
0
#if defined(CPPGC_CAGED_HEAP)
423
0
  // Caged heap already filters out sentinels.
424
0
  DijkstraMarkingBarrierSlow(object);
425
0
#else   // !CPPGC_CAGED_HEAP
426
0
  DijkstraMarkingBarrierSlowWithSentinelCheck(object);
427
0
#endif  // !CPPGC_CAGED_HEAP
428
0
}
429
430
// static
431
void WriteBarrier::DijkstraMarkingBarrierRange(const Params& params,
432
                                               const void* first_element,
433
                                               size_t element_size,
434
                                               size_t number_of_elements,
435
0
                                               TraceCallback trace_callback) {
436
0
  CheckParams(Type::kMarking, params);
437
0
  DijkstraMarkingBarrierRangeSlow(*params.heap, first_element, element_size,
438
0
                                  number_of_elements, trace_callback);
439
0
}
440
441
// static
442
void WriteBarrier::SteeleMarkingBarrier(const Params& params,
443
0
                                        const void* object) {
444
0
  CheckParams(Type::kMarking, params);
445
0
#if defined(CPPGC_CAGED_HEAP)
446
0
  // Caged heap already filters out sentinels.
447
0
  SteeleMarkingBarrierSlow(object);
448
0
#else   // !CPPGC_CAGED_HEAP
449
0
  SteeleMarkingBarrierSlowWithSentinelCheck(object);
450
0
#endif  // !CPPGC_CAGED_HEAP
451
0
}
452
453
#if defined(CPPGC_YOUNG_GENERATION)
454
455
// static
456
template <WriteBarrier::GenerationalBarrierType type>
457
void WriteBarrier::GenerationalBarrier(const Params& params, const void* slot) {
458
  CheckParams(Type::kGenerational, params);
459
460
  const CagedHeapLocalData& local_data = CagedHeapLocalData::Get();
461
  const AgeTable& age_table = local_data.age_table;
462
463
  // Bail out if the slot (precise or imprecise) is in young generation.
464
  if (V8_LIKELY(age_table.GetAge(params.slot_offset) == AgeTable::Age::kYoung))
465
    return;
466
467
  // Dispatch between different types of barriers.
468
  // TODO(chromium:1029379): Consider reload local_data in the slow path to
469
  // reduce register pressure.
470
  if constexpr (type == GenerationalBarrierType::kPreciseSlot) {
471
    GenerationalBarrierSlow(local_data, age_table, slot, params.value_offset,
472
                            params.heap);
473
  } else if constexpr (type ==
474
                       GenerationalBarrierType::kPreciseUncompressedSlot) {
475
    GenerationalBarrierForUncompressedSlotSlow(
476
        local_data, age_table, slot, params.value_offset, params.heap);
477
  } else {
478
    GenerationalBarrierForSourceObjectSlow(local_data, slot, params.heap);
479
  }
480
}
481
482
#endif  // !CPPGC_YOUNG_GENERATION
483
484
}  // namespace internal
485
}  // namespace cppgc
486
487
#endif  // INCLUDE_CPPGC_INTERNAL_WRITE_BARRIER_H_