1// Copyright 2015 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 V8_OBJECTS_OBJECTS_BODY_DESCRIPTORS_INL_H_
6#define V8_OBJECTS_OBJECTS_BODY_DESCRIPTORS_INL_H_
7
8#include <algorithm>
9
10#include "src/codegen/reloc-info.h"
11#include "src/ic/handler-configuration.h"
12#include "src/objects/arguments-inl.h"
13#include "src/objects/bigint.h"
14#include "src/objects/call-site-info.h"
15#include "src/objects/cell.h"
16#include "src/objects/data-handler.h"
17#include "src/objects/embedder-data-array-inl.h"
18#include "src/objects/fixed-array.h"
19#include "src/objects/foreign-inl.h"
20#include "src/objects/free-space-inl.h"
21#include "src/objects/hash-table.h"
22#include "src/objects/heap-number.h"
23#include "src/objects/js-collection.h"
24#include "src/objects/js-weak-refs.h"
25#include "src/objects/literal-objects.h"
26#include "src/objects/megadom-handler-inl.h"
27#include "src/objects/objects-body-descriptors.h"
28#include "src/objects/ordered-hash-table-inl.h"
29#include "src/objects/property-descriptor-object.h"
30#include "src/objects/source-text-module.h"
31#include "src/objects/swiss-name-dictionary-inl.h"
32#include "src/objects/synthetic-module.h"
33#include "src/objects/template-objects.h"
34#include "src/objects/torque-defined-classes-inl.h"
35#include "src/objects/transitions.h"
36#include "src/objects/turbofan-types-inl.h"
37
38#if V8_ENABLE_WEBASSEMBLY
39#include "src/wasm/wasm-objects-inl.h"
40#endif  // V8_ENABLE_WEBASSEMBLY
41
42namespace v8 {
43namespace internal {
44
45template <int start_offset>
46int FlexibleBodyDescriptor<start_offset>::SizeOf(Map map, HeapObject object) {
47  return object.SizeFromMap(map);
48}
49
50template <int start_offset>
51int FlexibleWeakBodyDescriptor<start_offset>::SizeOf(Map map,
52                                                     HeapObject object) {
53  return object.SizeFromMap(map);
54}
55
56bool BodyDescriptorBase::IsValidJSObjectSlotImpl(Map map, HeapObject obj,
57                                                 int offset) {
58#ifdef V8_COMPRESS_POINTERS
59  STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
60  int embedder_fields_offset = JSObject::GetEmbedderFieldsStartOffset(map);
61  int inobject_fields_offset = map.GetInObjectPropertyOffset(0);
62  // |embedder_fields_offset| may be greater than |inobject_fields_offset| if
63  // the object does not have embedder fields but the check handles this
64  // case properly.
65  if (embedder_fields_offset <= offset && offset < inobject_fields_offset) {
66    // offset points to embedder fields area:
67    // [embedder_fields_offset, inobject_fields_offset).
68    STATIC_ASSERT(base::bits::IsPowerOfTwo(kEmbedderDataSlotSize));
69    return ((offset - embedder_fields_offset) & (kEmbedderDataSlotSize - 1)) ==
70           EmbedderDataSlot::kTaggedPayloadOffset;
71  }
72#else
73  // We store raw aligned pointers as Smis, so it's safe to treat the whole
74  // embedder field area as tagged slots.
75  STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
76#endif
77  return true;
78}
79
80template <typename ObjectVisitor>
81void BodyDescriptorBase::IterateJSObjectBodyImpl(Map map, HeapObject obj,
82                                                 int start_offset,
83                                                 int end_offset,
84                                                 ObjectVisitor* v) {
85#ifdef V8_COMPRESS_POINTERS
86  STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
87  int header_end_offset = JSObject::GetHeaderSize(map);
88  int inobject_fields_start_offset = map.GetInObjectPropertyOffset(0);
89  // We are always requested to process header and embedder fields.
90  DCHECK_LE(inobject_fields_start_offset, end_offset);
91  // Embedder fields are located between header and inobject properties.
92  if (header_end_offset < inobject_fields_start_offset) {
93    // There are embedder fields.
94    DCHECK_EQ(header_end_offset, JSObject::GetEmbedderFieldsStartOffset(map));
95    IteratePointers(obj, start_offset, header_end_offset, v);
96    for (int offset = header_end_offset; offset < inobject_fields_start_offset;
97         offset += kEmbedderDataSlotSize) {
98      IteratePointer(obj, offset + EmbedderDataSlot::kTaggedPayloadOffset, v);
99      v->VisitExternalPointer(
100          obj, obj.RawExternalPointerField(
101                   offset + EmbedderDataSlot::kExternalPointerOffset));
102    }
103    // Proceed processing inobject properties.
104    start_offset = inobject_fields_start_offset;
105  }
106#else
107  // We store raw aligned pointers as Smis, so it's safe to iterate the whole
108  // embedder field area as tagged slots.
109  STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
110#endif
111  IteratePointers(obj, start_offset, end_offset, v);
112}
113
114template <typename ObjectVisitor>
115DISABLE_CFI_PERF void BodyDescriptorBase::IteratePointers(HeapObject obj,
116                                                          int start_offset,
117                                                          int end_offset,
118                                                          ObjectVisitor* v) {
119  if (start_offset == HeapObject::kMapOffset) {
120    v->VisitMapPointer(obj);
121    start_offset += kTaggedSize;
122  }
123  v->VisitPointers(obj, obj.RawField(start_offset), obj.RawField(end_offset));
124}
125
126template <typename ObjectVisitor>
127void BodyDescriptorBase::IteratePointer(HeapObject obj, int offset,
128                                        ObjectVisitor* v) {
129  DCHECK_NE(offset, HeapObject::kMapOffset);
130  v->VisitPointer(obj, obj.RawField(offset));
131}
132
133template <typename ObjectVisitor>
134DISABLE_CFI_PERF void BodyDescriptorBase::IterateMaybeWeakPointers(
135    HeapObject obj, int start_offset, int end_offset, ObjectVisitor* v) {
136  v->VisitPointers(obj, obj.RawMaybeWeakField(start_offset),
137                   obj.RawMaybeWeakField(end_offset));
138}
139
140template <typename ObjectVisitor>
141void BodyDescriptorBase::IterateMaybeWeakPointer(HeapObject obj, int offset,
142                                                 ObjectVisitor* v) {
143  DCHECK_NE(offset, HeapObject::kMapOffset);
144  v->VisitPointer(obj, obj.RawMaybeWeakField(offset));
145}
146
147template <typename ObjectVisitor>
148DISABLE_CFI_PERF void BodyDescriptorBase::IterateCustomWeakPointers(
149    HeapObject obj, int start_offset, int end_offset, ObjectVisitor* v) {
150  v->VisitCustomWeakPointers(obj, obj.RawField(start_offset),
151                             obj.RawField(end_offset));
152}
153
154template <typename ObjectVisitor>
155DISABLE_CFI_PERF void BodyDescriptorBase::IterateEphemeron(HeapObject obj,
156                                                           int index,
157                                                           int key_offset,
158                                                           int value_offset,
159                                                           ObjectVisitor* v) {
160  v->VisitEphemeron(obj, index, obj.RawField(key_offset),
161                    obj.RawField(value_offset));
162}
163
164template <typename ObjectVisitor>
165void BodyDescriptorBase::IterateCustomWeakPointer(HeapObject obj, int offset,
166                                                  ObjectVisitor* v) {
167  v->VisitCustomWeakPointer(obj, obj.RawField(offset));
168}
169
170class HeapNumber::BodyDescriptor final : public BodyDescriptorBase {
171 public:
172  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
173
174  template <typename ObjectVisitor>
175  static inline void IterateBody(Map map, HeapObject obj, int object_size,
176                                 ObjectVisitor* v) {}
177
178  static inline int SizeOf(Map map, HeapObject object) {
179    return HeapNumber::kSize;
180  }
181};
182
183// This is a descriptor for one/two pointer fillers.
184class FreeSpaceFillerBodyDescriptor final : public DataOnlyBodyDescriptor {
185 public:
186  static inline int SizeOf(Map map, HeapObject raw_object) {
187    return map.instance_size();
188  }
189};
190
191class FreeSpace::BodyDescriptor final : public DataOnlyBodyDescriptor {
192 public:
193  static inline int SizeOf(Map map, HeapObject raw_object) {
194    return FreeSpace::unchecked_cast(raw_object).Size();
195  }
196};
197
198class JSObject::BodyDescriptor final : public BodyDescriptorBase {
199 public:
200  static const int kStartOffset = JSReceiver::kPropertiesOrHashOffset;
201
202  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
203    if (offset < kStartOffset) return false;
204    return IsValidJSObjectSlotImpl(map, obj, offset);
205  }
206
207  template <typename ObjectVisitor>
208  static inline void IterateBody(Map map, HeapObject obj, int object_size,
209                                 ObjectVisitor* v) {
210    IterateJSObjectBodyImpl(map, obj, kStartOffset, object_size, v);
211  }
212
213  static inline int SizeOf(Map map, HeapObject object) {
214    return map.instance_size();
215  }
216};
217
218class JSObject::FastBodyDescriptor final : public BodyDescriptorBase {
219 public:
220  static const int kStartOffset = JSReceiver::kPropertiesOrHashOffset;
221
222  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
223    return offset >= kStartOffset;
224  }
225
226  template <typename ObjectVisitor>
227  static inline void IterateBody(Map map, HeapObject obj, int object_size,
228                                 ObjectVisitor* v) {
229    IteratePointers(obj, kStartOffset, object_size, v);
230  }
231
232  static inline int SizeOf(Map map, HeapObject object) {
233    return map.instance_size();
234  }
235};
236
237class WeakCell::BodyDescriptor final : public BodyDescriptorBase {
238 public:
239  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
240    return offset >= HeapObject::kHeaderSize;
241  }
242
243  template <typename ObjectVisitor>
244  static inline void IterateBody(Map map, HeapObject obj, int object_size,
245                                 ObjectVisitor* v) {
246    IteratePointers(obj, HeapObject::kHeaderSize, kTargetOffset, v);
247    IterateCustomWeakPointer(obj, kTargetOffset, v);
248    IterateCustomWeakPointer(obj, kUnregisterTokenOffset, v);
249    IteratePointers(obj, kUnregisterTokenOffset + kTaggedSize, object_size, v);
250  }
251
252  static inline int SizeOf(Map map, HeapObject object) {
253    return map.instance_size();
254  }
255};
256
257class JSWeakRef::BodyDescriptor final : public BodyDescriptorBase {
258 public:
259  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
260    return IsValidJSObjectSlotImpl(map, obj, offset);
261  }
262
263  template <typename ObjectVisitor>
264  static inline void IterateBody(Map map, HeapObject obj, int object_size,
265                                 ObjectVisitor* v) {
266    IteratePointers(obj, JSReceiver::kPropertiesOrHashOffset, kTargetOffset, v);
267    IterateCustomWeakPointer(obj, kTargetOffset, v);
268    IterateJSObjectBodyImpl(map, obj, kTargetOffset + kTaggedSize, object_size,
269                            v);
270  }
271
272  static inline int SizeOf(Map map, HeapObject object) {
273    return map.instance_size();
274  }
275};
276
277class JSFinalizationRegistry::BodyDescriptor final : public BodyDescriptorBase {
278 public:
279  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
280    return IsValidJSObjectSlotImpl(map, obj, offset);
281  }
282
283  template <typename ObjectVisitor>
284  static inline void IterateBody(Map map, HeapObject obj, int object_size,
285                                 ObjectVisitor* v) {
286    IteratePointers(obj, JSObject::BodyDescriptor::kStartOffset,
287                    kNextDirtyOffset, v);
288    IterateCustomWeakPointer(obj, kNextDirtyOffset, v);
289    IterateJSObjectBodyImpl(map, obj, kNextDirtyOffset + kTaggedSize,
290                            object_size, v);
291  }
292
293  static inline int SizeOf(Map map, HeapObject object) {
294    return map.instance_size();
295  }
296};
297
298class AllocationSite::BodyDescriptor final : public BodyDescriptorBase {
299 public:
300  STATIC_ASSERT(AllocationSite::kCommonPointerFieldEndOffset ==
301                AllocationSite::kPretenureDataOffset);
302  STATIC_ASSERT(AllocationSite::kPretenureDataOffset + kInt32Size ==
303                AllocationSite::kPretenureCreateCountOffset);
304  STATIC_ASSERT(AllocationSite::kPretenureCreateCountOffset + kInt32Size ==
305                AllocationSite::kWeakNextOffset);
306
307  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
308    if (offset >= AllocationSite::kStartOffset &&
309        offset < AllocationSite::kCommonPointerFieldEndOffset) {
310      return true;
311    }
312    // check for weak_next offset
313    if (map.instance_size() == AllocationSite::kSizeWithWeakNext &&
314        offset == AllocationSite::kWeakNextOffset) {
315      return true;
316    }
317    return false;
318  }
319
320  template <typename ObjectVisitor>
321  static inline void IterateBody(Map map, HeapObject obj, int object_size,
322                                 ObjectVisitor* v) {
323    // Iterate over all the common pointer fields
324    IteratePointers(obj, AllocationSite::kStartOffset,
325                    AllocationSite::kCommonPointerFieldEndOffset, v);
326    // Skip PretenureDataOffset and PretenureCreateCount which are Int32 fields.
327    // Visit weak_next only if it has weak_next field.
328    if (object_size == AllocationSite::kSizeWithWeakNext) {
329      IterateCustomWeakPointers(obj, AllocationSite::kWeakNextOffset,
330                                AllocationSite::kSizeWithWeakNext, v);
331    }
332  }
333
334  static inline int SizeOf(Map map, HeapObject object) {
335    return map.instance_size();
336  }
337};
338
339class JSFunction::BodyDescriptor final : public BodyDescriptorBase {
340 public:
341  static const int kStartOffset = JSObject::BodyDescriptor::kStartOffset;
342
343  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
344    if (offset < kStartOffset) return false;
345    return IsValidJSObjectSlotImpl(map, obj, offset);
346  }
347
348  template <typename ObjectVisitor>
349  static inline void IterateBody(Map map, HeapObject obj, int object_size,
350                                 ObjectVisitor* v) {
351    // Iterate JSFunction header fields first.
352    int header_size = JSFunction::GetHeaderSize(map.has_prototype_slot());
353    DCHECK_GE(object_size, header_size);
354    IteratePointers(obj, kStartOffset, kCodeOffset, v);
355    // Code field is treated as a custom weak pointer. This field is visited as
356    // a weak pointer if the Code is baseline code and the bytecode array
357    // corresponding to this function is old. In the rest of the cases this
358    // field is treated as strong pointer.
359    IterateCustomWeakPointer(obj, kCodeOffset, v);
360    // Iterate rest of the header fields
361    DCHECK_GE(header_size, kCodeOffset);
362    IteratePointers(obj, kCodeOffset + kTaggedSize, header_size, v);
363    // Iterate rest of the fields starting after the header.
364    IterateJSObjectBodyImpl(map, obj, header_size, object_size, v);
365  }
366
367  static inline int SizeOf(Map map, HeapObject object) {
368    return map.instance_size();
369  }
370};
371
372class JSArrayBuffer::BodyDescriptor final : public BodyDescriptorBase {
373 public:
374  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
375    if (offset < kEndOfTaggedFieldsOffset) return true;
376    if (offset < kHeaderSize) return false;
377    return IsValidJSObjectSlotImpl(map, obj, offset);
378  }
379
380  template <typename ObjectVisitor>
381  static inline void IterateBody(Map map, HeapObject obj, int object_size,
382                                 ObjectVisitor* v) {
383    // JSArrayBuffer instances contain raw data that the GC does not know about.
384    IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v);
385    IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v);
386  }
387
388  static inline int SizeOf(Map map, HeapObject object) {
389    return map.instance_size();
390  }
391};
392
393class JSTypedArray::BodyDescriptor final : public BodyDescriptorBase {
394 public:
395  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
396    if (offset < kEndOfTaggedFieldsOffset) return true;
397    // TODO(v8:4153): Remove this.
398    if (offset == kBasePointerOffset) return true;
399    if (offset < kHeaderSize) return false;
400    return IsValidJSObjectSlotImpl(map, obj, offset);
401  }
402
403  template <typename ObjectVisitor>
404  static inline void IterateBody(Map map, HeapObject obj, int object_size,
405                                 ObjectVisitor* v) {
406    // JSTypedArray contains raw data that the GC does not know about.
407    IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v);
408    // TODO(v8:4153): Remove this.
409    IteratePointer(obj, kBasePointerOffset, v);
410    IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v);
411  }
412
413  static inline int SizeOf(Map map, HeapObject object) {
414    return map.instance_size();
415  }
416};
417
418class JSDataView::BodyDescriptor final : public BodyDescriptorBase {
419 public:
420  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
421    if (offset < kEndOfTaggedFieldsOffset) return true;
422    if (offset < kHeaderSize) return false;
423    return IsValidJSObjectSlotImpl(map, obj, offset);
424  }
425
426  template <typename ObjectVisitor>
427  static inline void IterateBody(Map map, HeapObject obj, int object_size,
428                                 ObjectVisitor* v) {
429    // JSDataView contains raw data that the GC does not know about.
430    IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v);
431    IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v);
432  }
433
434  static inline int SizeOf(Map map, HeapObject object) {
435    return map.instance_size();
436  }
437};
438
439class JSExternalObject::BodyDescriptor final : public BodyDescriptorBase {
440 public:
441  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
442
443  template <typename ObjectVisitor>
444  static inline void IterateBody(Map map, HeapObject obj, int object_size,
445                                 ObjectVisitor* v) {
446    IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v);
447    v->VisitExternalPointer(obj, obj.RawExternalPointerField(kValueOffset));
448  }
449
450  static inline int SizeOf(Map map, HeapObject object) {
451    return map.instance_size();
452  }
453};
454
455template <typename Derived>
456class V8_EXPORT_PRIVATE SmallOrderedHashTable<Derived>::BodyDescriptor final
457    : public BodyDescriptorBase {
458 public:
459  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
460    Derived table = Derived::cast(obj);
461    // Only data table part contains tagged values.
462    return (offset >= DataTableStartOffset()) &&
463           (offset < table.GetBucketsStartOffset());
464  }
465
466  template <typename ObjectVisitor>
467  static inline void IterateBody(Map map, HeapObject obj, int object_size,
468                                 ObjectVisitor* v) {
469    Derived table = Derived::cast(obj);
470    int start_offset = DataTableStartOffset();
471    int end_offset = table.GetBucketsStartOffset();
472    IteratePointers(obj, start_offset, end_offset, v);
473  }
474
475  static inline int SizeOf(Map map, HeapObject obj) {
476    Derived table = Derived::cast(obj);
477    return Derived::SizeFor(table.Capacity());
478  }
479};
480
481class V8_EXPORT_PRIVATE SwissNameDictionary::BodyDescriptor final
482    : public BodyDescriptorBase {
483 public:
484  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
485    // Using |unchecked_cast| here and elsewhere in this class because the
486    // Scavenger may be calling us while the map word contains the forwarding
487    // address (a Smi) rather than a map.
488
489    SwissNameDictionary table = SwissNameDictionary::unchecked_cast(obj);
490    STATIC_ASSERT(MetaTablePointerOffset() + kTaggedSize ==
491                  DataTableStartOffset());
492    return offset >= MetaTablePointerOffset() &&
493           (offset < table.DataTableEndOffset(table.Capacity()));
494  }
495
496  template <typename ObjectVisitor>
497  static inline void IterateBody(Map map, HeapObject obj, int object_size,
498                                 ObjectVisitor* v) {
499    SwissNameDictionary table = SwissNameDictionary::unchecked_cast(obj);
500    STATIC_ASSERT(MetaTablePointerOffset() + kTaggedSize ==
501                  DataTableStartOffset());
502    int start_offset = MetaTablePointerOffset();
503    int end_offset = table.DataTableEndOffset(table.Capacity());
504    IteratePointers(obj, start_offset, end_offset, v);
505  }
506
507  static inline int SizeOf(Map map, HeapObject obj) {
508    SwissNameDictionary table = SwissNameDictionary::unchecked_cast(obj);
509    return SwissNameDictionary::SizeFor(table.Capacity());
510  }
511};
512
513class ByteArray::BodyDescriptor final : public BodyDescriptorBase {
514 public:
515  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
516
517  template <typename ObjectVisitor>
518  static inline void IterateBody(Map map, HeapObject obj, int object_size,
519                                 ObjectVisitor* v) {}
520
521  static inline int SizeOf(Map map, HeapObject obj) {
522    return ByteArray::SizeFor(ByteArray::cast(obj).length(kAcquireLoad));
523  }
524};
525
526class BytecodeArray::BodyDescriptor final : public BodyDescriptorBase {
527 public:
528  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
529    return offset >= kConstantPoolOffset &&
530           offset <= kSourcePositionTableOffset;
531  }
532
533  template <typename ObjectVisitor>
534  static inline void IterateBody(Map map, HeapObject obj, int object_size,
535                                 ObjectVisitor* v) {
536    IteratePointer(obj, kConstantPoolOffset, v);
537    IteratePointer(obj, kHandlerTableOffset, v);
538    IteratePointer(obj, kSourcePositionTableOffset, v);
539  }
540
541  static inline int SizeOf(Map map, HeapObject obj) {
542    return BytecodeArray::SizeFor(
543        BytecodeArray::cast(obj).length(kAcquireLoad));
544  }
545};
546
547class BigInt::BodyDescriptor final : public BodyDescriptorBase {
548 public:
549  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
550
551  template <typename ObjectVisitor>
552  static inline void IterateBody(Map map, HeapObject obj, int object_size,
553                                 ObjectVisitor* v) {}
554
555  static inline int SizeOf(Map map, HeapObject obj) {
556    return BigInt::SizeFor(BigInt::cast(obj).length(kAcquireLoad));
557  }
558};
559
560class FixedDoubleArray::BodyDescriptor final : public BodyDescriptorBase {
561 public:
562  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
563
564  template <typename ObjectVisitor>
565  static inline void IterateBody(Map map, HeapObject obj, int object_size,
566                                 ObjectVisitor* v) {}
567
568  static inline int SizeOf(Map map, HeapObject obj) {
569    return FixedDoubleArray::SizeFor(
570        FixedDoubleArray::cast(obj).length(kAcquireLoad));
571  }
572};
573
574class FeedbackMetadata::BodyDescriptor final : public BodyDescriptorBase {
575 public:
576  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
577
578  template <typename ObjectVisitor>
579  static inline void IterateBody(Map map, HeapObject obj, int object_size,
580                                 ObjectVisitor* v) {}
581
582  static inline int SizeOf(Map map, HeapObject obj) {
583    return FeedbackMetadata::SizeFor(
584        FeedbackMetadata::cast(obj).slot_count(kAcquireLoad));
585  }
586};
587
588class PreparseData::BodyDescriptor final : public BodyDescriptorBase {
589 public:
590  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
591    return offset >= PreparseData::cast(obj).inner_start_offset();
592  }
593
594  template <typename ObjectVisitor>
595  static inline void IterateBody(Map map, HeapObject obj, int object_size,
596                                 ObjectVisitor* v) {
597    PreparseData data = PreparseData::cast(obj);
598    int start_offset = data.inner_start_offset();
599    int end_offset = start_offset + data.children_length() * kTaggedSize;
600    IteratePointers(obj, start_offset, end_offset, v);
601  }
602
603  static inline int SizeOf(Map map, HeapObject obj) {
604    PreparseData data = PreparseData::cast(obj);
605    return PreparseData::SizeFor(data.data_length(), data.children_length());
606  }
607};
608
609class PromiseOnStack::BodyDescriptor final : public BodyDescriptorBase {
610 public:
611  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
612    return offset >= HeapObject::kHeaderSize;
613  }
614
615  template <typename ObjectVisitor>
616  static inline void IterateBody(Map map, HeapObject obj, int object_size,
617                                 ObjectVisitor* v) {
618    IteratePointers(obj, Struct::kHeaderSize, kPromiseOffset, v);
619    IterateMaybeWeakPointer(obj, kPromiseOffset, v);
620    STATIC_ASSERT(kPromiseOffset + kTaggedSize == kHeaderSize);
621  }
622
623  static inline int SizeOf(Map map, HeapObject obj) {
624    return obj.SizeFromMap(map);
625  }
626};
627
628class PrototypeInfo::BodyDescriptor final : public BodyDescriptorBase {
629 public:
630  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
631    return offset >= HeapObject::kHeaderSize;
632  }
633
634  template <typename ObjectVisitor>
635  static inline void IterateBody(Map map, HeapObject obj, int object_size,
636                                 ObjectVisitor* v) {
637    IteratePointers(obj, HeapObject::kHeaderSize, kObjectCreateMapOffset, v);
638    IterateMaybeWeakPointer(obj, kObjectCreateMapOffset, v);
639    STATIC_ASSERT(kObjectCreateMapOffset + kTaggedSize == kHeaderSize);
640  }
641
642  static inline int SizeOf(Map map, HeapObject obj) {
643    return obj.SizeFromMap(map);
644  }
645};
646
647class JSWeakCollection::BodyDescriptorImpl final : public BodyDescriptorBase {
648 public:
649  STATIC_ASSERT(kTableOffset + kTaggedSize == kHeaderSizeOfAllWeakCollections);
650
651  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
652    return IsValidJSObjectSlotImpl(map, obj, offset);
653  }
654
655  template <typename ObjectVisitor>
656  static inline void IterateBody(Map map, HeapObject obj, int object_size,
657                                 ObjectVisitor* v) {
658    IterateJSObjectBodyImpl(map, obj, kPropertiesOrHashOffset, object_size, v);
659  }
660
661  static inline int SizeOf(Map map, HeapObject object) {
662    return map.instance_size();
663  }
664};
665
666class Foreign::BodyDescriptor final : public BodyDescriptorBase {
667 public:
668  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
669
670  template <typename ObjectVisitor>
671  static inline void IterateBody(Map map, HeapObject obj, int object_size,
672                                 ObjectVisitor* v) {
673    v->VisitExternalReference(
674        Foreign::cast(obj), reinterpret_cast<Address*>(
675                                obj.RawField(kForeignAddressOffset).address()));
676    v->VisitExternalPointer(obj,
677                            obj.RawExternalPointerField(kForeignAddressOffset));
678  }
679
680  static inline int SizeOf(Map map, HeapObject object) { return kSize; }
681};
682
683#if V8_ENABLE_WEBASSEMBLY
684class WasmTypeInfo::BodyDescriptor final : public BodyDescriptorBase {
685 public:
686  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
687    UNREACHABLE();
688  }
689
690  template <typename ObjectVisitor>
691  static inline void IterateBody(Map map, HeapObject obj, int object_size,
692                                 ObjectVisitor* v) {
693    Foreign::BodyDescriptor::IterateBody<ObjectVisitor>(map, obj, object_size,
694                                                        v);
695    IteratePointer(obj, kSupertypesOffset, v);
696    IteratePointer(obj, kSubtypesOffset, v);
697    IteratePointer(obj, kInstanceOffset, v);
698  }
699
700  static inline int SizeOf(Map map, HeapObject object) { return kSize; }
701};
702
703class WasmApiFunctionRef::BodyDescriptor final : public BodyDescriptorBase {
704 public:
705  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
706    UNREACHABLE();
707  }
708
709  template <typename ObjectVisitor>
710  static inline void IterateBody(Map map, HeapObject obj, int object_size,
711                                 ObjectVisitor* v) {
712    IteratePointers(obj, kStartOfStrongFieldsOffset, kEndOfStrongFieldsOffset,
713                    v);
714  }
715
716  static inline int SizeOf(Map map, HeapObject object) { return kSize; }
717};
718
719class WasmInternalFunction::BodyDescriptor final : public BodyDescriptorBase {
720 public:
721  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
722    UNREACHABLE();
723  }
724
725  template <typename ObjectVisitor>
726  static inline void IterateBody(Map map, HeapObject obj, int object_size,
727                                 ObjectVisitor* v) {
728    Foreign::BodyDescriptor::IterateBody<ObjectVisitor>(map, obj, object_size,
729                                                        v);
730    IteratePointers(obj, kStartOfStrongFieldsOffset, kEndOfStrongFieldsOffset,
731                    v);
732  }
733
734  static inline int SizeOf(Map map, HeapObject object) { return kSize; }
735};
736
737class WasmInstanceObject::BodyDescriptor final : public BodyDescriptorBase {
738 public:
739  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
740    SLOW_DCHECK(std::is_sorted(std::begin(kTaggedFieldOffsets),
741                               std::end(kTaggedFieldOffsets)));
742    STATIC_ASSERT(sizeof(*kTaggedFieldOffsets) == sizeof(uint16_t));
743    if (offset < int{8 * sizeof(*kTaggedFieldOffsets)} &&
744        std::binary_search(std::begin(kTaggedFieldOffsets),
745                           std::end(kTaggedFieldOffsets),
746                           static_cast<uint16_t>(offset))) {
747      return true;
748    }
749    return IsValidJSObjectSlotImpl(map, obj, offset);
750  }
751
752  template <typename ObjectVisitor>
753  static inline void IterateBody(Map map, HeapObject obj, int object_size,
754                                 ObjectVisitor* v) {
755    IteratePointers(obj, kPropertiesOrHashOffset, JSObject::kHeaderSize, v);
756    for (uint16_t offset : kTaggedFieldOffsets) {
757      IteratePointer(obj, offset, v);
758    }
759    IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v);
760  }
761
762  static inline int SizeOf(Map map, HeapObject object) {
763    return map.instance_size();
764  }
765};
766
767class WasmArray::BodyDescriptor final : public BodyDescriptorBase {
768 public:
769  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
770    // Fields in WasmArrays never change their types in place, so
771    // there should never be a need to call this function.
772    UNREACHABLE();
773    return false;
774  }
775
776  template <typename ObjectVisitor>
777  static inline void IterateBody(Map map, HeapObject obj, int object_size,
778                                 ObjectVisitor* v) {
779    // The type is safe to use because it's kept alive by the {map}'s
780    // WasmTypeInfo.
781    if (!WasmArray::GcSafeType(map)->element_type().is_reference()) return;
782    IteratePointers(obj, WasmArray::kHeaderSize, object_size, v);
783  }
784
785  static inline int SizeOf(Map map, HeapObject object) {
786    return WasmArray::SizeFor(map, WasmArray::cast(object).length());
787  }
788};
789
790class WasmStruct::BodyDescriptor final : public BodyDescriptorBase {
791 public:
792  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
793    // Fields in WasmStructs never change their types in place, so
794    // there should never be a need to call this function.
795    UNREACHABLE();
796    return false;
797  }
798
799  template <typename ObjectVisitor>
800  static inline void IterateBody(Map map, HeapObject obj, int object_size,
801                                 ObjectVisitor* v) {
802    WasmStruct wasm_struct = WasmStruct::cast(obj);
803    // The {type} is safe to use because it's kept alive by the {map}'s
804    // WasmTypeInfo.
805    wasm::StructType* type = WasmStruct::GcSafeType(map);
806    for (uint32_t i = 0; i < type->field_count(); i++) {
807      if (!type->field(i).is_reference()) continue;
808      int offset = static_cast<int>(type->field_offset(i));
809      v->VisitPointer(wasm_struct, wasm_struct.RawField(offset));
810    }
811  }
812
813  static inline int SizeOf(Map map, HeapObject object) {
814    return WasmStruct::GcSafeSize(map);
815  }
816};
817
818#endif  // V8_ENABLE_WEBASSEMBLY
819
820class ExternalOneByteString::BodyDescriptor final : public BodyDescriptorBase {
821 public:
822  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
823
824  template <typename ObjectVisitor>
825  static inline void IterateBody(Map map, HeapObject obj, int object_size,
826                                 ObjectVisitor* v) {
827    ExternalString string = ExternalString::cast(obj);
828    v->VisitExternalPointer(obj,
829                            string.RawExternalPointerField(kResourceOffset));
830    if (string.is_uncached()) return;
831    v->VisitExternalPointer(
832        obj, string.RawExternalPointerField(kResourceDataOffset));
833  }
834
835  static inline int SizeOf(Map map, HeapObject object) { return kSize; }
836};
837
838class ExternalTwoByteString::BodyDescriptor final : public BodyDescriptorBase {
839 public:
840  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
841
842  template <typename ObjectVisitor>
843  static inline void IterateBody(Map map, HeapObject obj, int object_size,
844                                 ObjectVisitor* v) {
845    ExternalString string = ExternalString::cast(obj);
846    v->VisitExternalPointer(obj,
847                            string.RawExternalPointerField(kResourceOffset));
848    if (string.is_uncached()) return;
849    v->VisitExternalPointer(
850        obj, string.RawExternalPointerField(kResourceDataOffset));
851  }
852
853  static inline int SizeOf(Map map, HeapObject object) { return kSize; }
854};
855
856class CoverageInfo::BodyDescriptor final : public BodyDescriptorBase {
857 public:
858  static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
859
860  template <typename ObjectVisitor>
861  static inline void IterateBody(Map map, HeapObject obj, int object_size,
862                                 ObjectVisitor* v) {}
863
864  static inline int SizeOf(Map map, HeapObject object) {
865    CoverageInfo info = CoverageInfo::cast(object);
866    return CoverageInfo::SizeFor(info.slot_count());
867  }
868};
869
870class Code::BodyDescriptor final : public BodyDescriptorBase {
871 public:
872  STATIC_ASSERT(kRelocationInfoOffset + kTaggedSize ==
873                kDeoptimizationDataOrInterpreterDataOffset);
874  STATIC_ASSERT(kDeoptimizationDataOrInterpreterDataOffset + kTaggedSize ==
875                kPositionTableOffset);
876  STATIC_ASSERT(kPositionTableOffset + kTaggedSize == kCodeDataContainerOffset);
877  STATIC_ASSERT(kCodeDataContainerOffset + kTaggedSize == kDataStart);
878
879  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
880    // Slots in code can't be invalid because we never trim code objects.
881    return true;
882  }
883
884  static constexpr int kRelocModeMask =
885      RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
886      RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
887      RelocInfo::ModeMask(RelocInfo::FULL_EMBEDDED_OBJECT) |
888      RelocInfo::ModeMask(RelocInfo::COMPRESSED_EMBEDDED_OBJECT) |
889      RelocInfo::ModeMask(RelocInfo::DATA_EMBEDDED_OBJECT) |
890      RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
891      RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
892      RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
893      RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) |
894      RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
895
896  template <typename ObjectVisitor>
897  static inline void IterateBody(Map map, HeapObject obj, ObjectVisitor* v) {
898    // GC does not visit data/code in the header and in the body directly.
899    IteratePointers(obj, kRelocationInfoOffset, kDataStart, v);
900
901    RelocIterator it(Code::cast(obj), kRelocModeMask);
902    v->VisitRelocInfo(&it);
903  }
904
905  template <typename ObjectVisitor>
906  static inline void IterateBody(Map map, HeapObject obj, int object_size,
907                                 ObjectVisitor* v) {
908    IterateBody(map, obj, v);
909  }
910
911  static inline int SizeOf(Map map, HeapObject object) {
912    return Code::unchecked_cast(object).CodeSize();
913  }
914};
915
916class Map::BodyDescriptor final : public BodyDescriptorBase {
917 public:
918  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
919    static_assert(
920        Map::kEndOfStrongFieldsOffset == Map::kStartOfWeakFieldsOffset,
921        "Leverage that weak fields directly follow strong fields for the "
922        "check below");
923    return offset >= Map::kStartOfStrongFieldsOffset &&
924           offset < Map::kEndOfWeakFieldsOffset;
925  }
926
927  template <typename ObjectVisitor>
928  static inline void IterateBody(Map map, HeapObject obj, int object_size,
929                                 ObjectVisitor* v) {
930    IteratePointers(obj, Map::kStartOfStrongFieldsOffset,
931                    Map::kEndOfStrongFieldsOffset, v);
932    IterateMaybeWeakPointer(obj, kTransitionsOrPrototypeInfoOffset, v);
933  }
934
935  static inline int SizeOf(Map map, HeapObject obj) { return Map::kSize; }
936};
937
938class DataHandler::BodyDescriptor final : public BodyDescriptorBase {
939 public:
940  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
941    return offset >= HeapObject::kHeaderSize;
942  }
943
944  template <typename ObjectVisitor>
945  static inline void IterateBody(Map map, HeapObject obj, int object_size,
946                                 ObjectVisitor* v) {
947    static_assert(kSmiHandlerOffset < kData1Offset,
948                  "Field order must be in sync with this iteration code");
949    static_assert(kData1Offset < kSizeWithData1,
950                  "Field order must be in sync with this iteration code");
951    IteratePointers(obj, kSmiHandlerOffset, kData1Offset, v);
952    IterateMaybeWeakPointers(obj, kData1Offset, object_size, v);
953  }
954
955  static inline int SizeOf(Map map, HeapObject object) {
956    return object.SizeFromMap(map);
957  }
958};
959
960class NativeContext::BodyDescriptor final : public BodyDescriptorBase {
961 public:
962  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
963    return offset < NativeContext::kEndOfTaggedFieldsOffset;
964  }
965
966  template <typename ObjectVisitor>
967  static inline void IterateBody(Map map, HeapObject obj, int object_size,
968                                 ObjectVisitor* v) {
969    IteratePointers(obj, NativeContext::kStartOfStrongFieldsOffset,
970                    NativeContext::kEndOfStrongFieldsOffset, v);
971    IterateCustomWeakPointers(obj, NativeContext::kStartOfWeakFieldsOffset,
972                              NativeContext::kEndOfWeakFieldsOffset, v);
973    v->VisitExternalPointer(obj,
974                            obj.RawExternalPointerField(kMicrotaskQueueOffset));
975  }
976
977  static inline int SizeOf(Map map, HeapObject object) {
978    return NativeContext::kSize;
979  }
980};
981
982class CodeDataContainer::BodyDescriptor final : public BodyDescriptorBase {
983 public:
984  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
985    return offset >= CodeDataContainer::kHeaderSize &&
986           offset <= CodeDataContainer::kPointerFieldsWeakEndOffset;
987  }
988
989  template <typename ObjectVisitor>
990  static inline void IterateBody(Map map, HeapObject obj, int object_size,
991                                 ObjectVisitor* v) {
992    IteratePointers(obj, CodeDataContainer::kHeaderSize,
993                    CodeDataContainer::kPointerFieldsStrongEndOffset, v);
994    IterateCustomWeakPointers(
995        obj, CodeDataContainer::kPointerFieldsStrongEndOffset,
996        CodeDataContainer::kPointerFieldsWeakEndOffset, v);
997
998    if (V8_EXTERNAL_CODE_SPACE_BOOL) {
999      v->VisitCodePointer(obj, obj.RawCodeField(kCodeOffset));
1000      v->VisitExternalPointer(
1001          obj, obj.RawExternalPointerField(kCodeEntryPointOffset));
1002    }
1003  }
1004
1005  static inline int SizeOf(Map map, HeapObject object) {
1006    return CodeDataContainer::kSize;
1007  }
1008};
1009
1010class EmbedderDataArray::BodyDescriptor final : public BodyDescriptorBase {
1011 public:
1012  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
1013#ifdef V8_COMPRESS_POINTERS
1014    STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
1015    STATIC_ASSERT(base::bits::IsPowerOfTwo(kEmbedderDataSlotSize));
1016    return (offset < EmbedderDataArray::kHeaderSize) ||
1017           (((offset - EmbedderDataArray::kHeaderSize) &
1018             (kEmbedderDataSlotSize - 1)) ==
1019            EmbedderDataSlot::kTaggedPayloadOffset);
1020#else
1021    STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
1022    // We store raw aligned pointers as Smis, so it's safe to iterate the whole
1023    // array.
1024    return true;
1025#endif
1026  }
1027
1028  template <typename ObjectVisitor>
1029  static inline void IterateBody(Map map, HeapObject obj, int object_size,
1030                                 ObjectVisitor* v) {
1031#ifdef V8_COMPRESS_POINTERS
1032    STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
1033    for (int offset = EmbedderDataArray::OffsetOfElementAt(0);
1034         offset < object_size; offset += kEmbedderDataSlotSize) {
1035      IteratePointer(obj, offset + EmbedderDataSlot::kTaggedPayloadOffset, v);
1036      v->VisitExternalPointer(
1037          obj, obj.RawExternalPointerField(
1038                   offset + EmbedderDataSlot::kExternalPointerOffset));
1039    }
1040
1041#else
1042    // We store raw aligned pointers as Smis, so it's safe to iterate the whole
1043    // array.
1044    STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
1045    IteratePointers(obj, EmbedderDataArray::kHeaderSize, object_size, v);
1046#endif
1047  }
1048
1049  static inline int SizeOf(Map map, HeapObject object) {
1050    return object.SizeFromMap(map);
1051  }
1052};
1053
1054template <typename Op, typename... Args>
1055auto BodyDescriptorApply(InstanceType type, Args&&... args) {
1056#define CALL_APPLY(ClassName) \
1057  Op::template apply<ClassName::BodyDescriptor>(std::forward<Args>(args)...)
1058
1059  if (type < FIRST_NONSTRING_TYPE) {
1060    switch (type & kStringRepresentationMask) {
1061      case kSeqStringTag:
1062        if ((type & kStringEncodingMask) == kOneByteStringTag) {
1063          return CALL_APPLY(SeqOneByteString);
1064        } else {
1065          return CALL_APPLY(SeqTwoByteString);
1066        }
1067      case kConsStringTag:
1068        return CALL_APPLY(ConsString);
1069      case kThinStringTag:
1070        return CALL_APPLY(ThinString);
1071      case kSlicedStringTag:
1072        return CALL_APPLY(SlicedString);
1073      case kExternalStringTag:
1074        if ((type & kStringEncodingMask) == kOneByteStringTag) {
1075          return CALL_APPLY(ExternalOneByteString);
1076        } else {
1077          return CALL_APPLY(ExternalTwoByteString);
1078        }
1079    }
1080    UNREACHABLE();
1081  }
1082  if (InstanceTypeChecker::IsJSApiObject(type)) {
1083    return CALL_APPLY(JSObject);
1084  }
1085
1086  switch (type) {
1087    case EMBEDDER_DATA_ARRAY_TYPE:
1088      return CALL_APPLY(EmbedderDataArray);
1089    case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
1090    case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE:
1091    case HASH_TABLE_TYPE:
1092    case ORDERED_HASH_MAP_TYPE:
1093    case ORDERED_HASH_SET_TYPE:
1094    case ORDERED_NAME_DICTIONARY_TYPE:
1095    case NAME_DICTIONARY_TYPE:
1096    case GLOBAL_DICTIONARY_TYPE:
1097    case NUMBER_DICTIONARY_TYPE:
1098    case SIMPLE_NUMBER_DICTIONARY_TYPE:
1099    case NAME_TO_INDEX_HASH_TABLE_TYPE:
1100    case REGISTERED_SYMBOL_TABLE_TYPE:
1101    case SCRIPT_CONTEXT_TABLE_TYPE:
1102      return CALL_APPLY(FixedArray);
1103    case EPHEMERON_HASH_TABLE_TYPE:
1104      return CALL_APPLY(EphemeronHashTable);
1105    case AWAIT_CONTEXT_TYPE:
1106    case BLOCK_CONTEXT_TYPE:
1107    case CATCH_CONTEXT_TYPE:
1108    case DEBUG_EVALUATE_CONTEXT_TYPE:
1109    case EVAL_CONTEXT_TYPE:
1110    case FUNCTION_CONTEXT_TYPE:
1111    case MODULE_CONTEXT_TYPE:
1112    case SCRIPT_CONTEXT_TYPE:
1113    case WITH_CONTEXT_TYPE:
1114      return CALL_APPLY(Context);
1115    case NATIVE_CONTEXT_TYPE:
1116      return CALL_APPLY(NativeContext);
1117    case FIXED_DOUBLE_ARRAY_TYPE:
1118      return CALL_APPLY(FixedDoubleArray);
1119    case FEEDBACK_METADATA_TYPE:
1120      return CALL_APPLY(FeedbackMetadata);
1121    case PROPERTY_ARRAY_TYPE:
1122      return CALL_APPLY(PropertyArray);
1123    case TRANSITION_ARRAY_TYPE:
1124      return CALL_APPLY(TransitionArray);
1125    case FEEDBACK_CELL_TYPE:
1126      return CALL_APPLY(FeedbackCell);
1127    case COVERAGE_INFO_TYPE:
1128      return CALL_APPLY(CoverageInfo);
1129#if V8_ENABLE_WEBASSEMBLY
1130    case WASM_API_FUNCTION_REF_TYPE:
1131      return CALL_APPLY(WasmApiFunctionRef);
1132    case WASM_ARRAY_TYPE:
1133      return CALL_APPLY(WasmArray);
1134    case WASM_CAPI_FUNCTION_DATA_TYPE:
1135      return CALL_APPLY(WasmCapiFunctionData);
1136    case WASM_EXPORTED_FUNCTION_DATA_TYPE:
1137      return CALL_APPLY(WasmExportedFunctionData);
1138    case WASM_INTERNAL_FUNCTION_TYPE:
1139      return CALL_APPLY(WasmInternalFunction);
1140    case WASM_JS_FUNCTION_DATA_TYPE:
1141      return CALL_APPLY(WasmJSFunctionData);
1142    case WASM_ON_FULFILLED_DATA_TYPE:
1143      return CALL_APPLY(WasmOnFulfilledData);
1144    case WASM_STRUCT_TYPE:
1145      return CALL_APPLY(WasmStruct);
1146    case WASM_TYPE_INFO_TYPE:
1147      return CALL_APPLY(WasmTypeInfo);
1148#endif  // V8_ENABLE_WEBASSEMBLY
1149    case JS_API_OBJECT_TYPE:
1150    case JS_ARGUMENTS_OBJECT_TYPE:
1151    case JS_ARRAY_ITERATOR_PROTOTYPE_TYPE:
1152    case JS_ARRAY_ITERATOR_TYPE:
1153    case JS_ARRAY_TYPE:
1154    case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
1155    case JS_ASYNC_FUNCTION_OBJECT_TYPE:
1156    case JS_ASYNC_GENERATOR_OBJECT_TYPE:
1157    case JS_BOUND_FUNCTION_TYPE:
1158    case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1159    case JS_DATE_TYPE:
1160    case JS_ERROR_TYPE:
1161    case JS_FINALIZATION_REGISTRY_TYPE:
1162    case JS_GENERATOR_OBJECT_TYPE:
1163    case JS_GLOBAL_OBJECT_TYPE:
1164    case JS_GLOBAL_PROXY_TYPE:
1165    case JS_ITERATOR_PROTOTYPE_TYPE:
1166    case JS_MAP_ITERATOR_PROTOTYPE_TYPE:
1167    case JS_MAP_KEY_ITERATOR_TYPE:
1168    case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
1169    case JS_MAP_TYPE:
1170    case JS_MAP_VALUE_ITERATOR_TYPE:
1171    case JS_MESSAGE_OBJECT_TYPE:
1172    case JS_MODULE_NAMESPACE_TYPE:
1173    case JS_OBJECT_PROTOTYPE_TYPE:
1174    case JS_OBJECT_TYPE:
1175    case JS_PRIMITIVE_WRAPPER_TYPE:
1176    case JS_PROMISE_PROTOTYPE_TYPE:
1177    case JS_PROMISE_TYPE:
1178    case JS_REG_EXP_PROTOTYPE_TYPE:
1179    case JS_REG_EXP_STRING_ITERATOR_TYPE:
1180    case JS_REG_EXP_TYPE:
1181    case JS_SET_ITERATOR_PROTOTYPE_TYPE:
1182    case JS_SET_KEY_VALUE_ITERATOR_TYPE:
1183    case JS_SET_PROTOTYPE_TYPE:
1184    case JS_SET_TYPE:
1185    case JS_SET_VALUE_ITERATOR_TYPE:
1186    case JS_SPECIAL_API_OBJECT_TYPE:
1187    case JS_SHADOW_REALM_TYPE:
1188    case JS_SHARED_STRUCT_TYPE:
1189    case JS_STRING_ITERATOR_PROTOTYPE_TYPE:
1190    case JS_STRING_ITERATOR_TYPE:
1191    case JS_TEMPORAL_CALENDAR_TYPE:
1192    case JS_TEMPORAL_DURATION_TYPE:
1193    case JS_TEMPORAL_INSTANT_TYPE:
1194    case JS_TEMPORAL_PLAIN_DATE_TYPE:
1195    case JS_TEMPORAL_PLAIN_DATE_TIME_TYPE:
1196    case JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE:
1197    case JS_TEMPORAL_PLAIN_TIME_TYPE:
1198    case JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE:
1199    case JS_TEMPORAL_TIME_ZONE_TYPE:
1200    case JS_TEMPORAL_ZONED_DATE_TIME_TYPE:
1201    case JS_TYPED_ARRAY_PROTOTYPE_TYPE:
1202    case JS_FUNCTION_TYPE:
1203    case JS_CLASS_CONSTRUCTOR_TYPE:
1204    case JS_PROMISE_CONSTRUCTOR_TYPE:
1205    case JS_REG_EXP_CONSTRUCTOR_TYPE:
1206    case JS_WRAPPED_FUNCTION_TYPE:
1207    case JS_ARRAY_CONSTRUCTOR_TYPE:
1208#define TYPED_ARRAY_CONSTRUCTORS_SWITCH(Type, type, TYPE, Ctype) \
1209  case TYPE##_TYPED_ARRAY_CONSTRUCTOR_TYPE:
1210      TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTORS_SWITCH)
1211#undef TYPED_ARRAY_CONSTRUCTORS_SWITCH
1212#ifdef V8_INTL_SUPPORT
1213    case JS_V8_BREAK_ITERATOR_TYPE:
1214    case JS_COLLATOR_TYPE:
1215    case JS_DATE_TIME_FORMAT_TYPE:
1216    case JS_DISPLAY_NAMES_TYPE:
1217    case JS_LIST_FORMAT_TYPE:
1218    case JS_LOCALE_TYPE:
1219    case JS_NUMBER_FORMAT_TYPE:
1220    case JS_PLURAL_RULES_TYPE:
1221    case JS_RELATIVE_TIME_FORMAT_TYPE:
1222    case JS_SEGMENT_ITERATOR_TYPE:
1223    case JS_SEGMENTER_TYPE:
1224    case JS_SEGMENTS_TYPE:
1225#endif  // V8_INTL_SUPPORT
1226#if V8_ENABLE_WEBASSEMBLY
1227    case WASM_GLOBAL_OBJECT_TYPE:
1228    case WASM_MEMORY_OBJECT_TYPE:
1229    case WASM_MODULE_OBJECT_TYPE:
1230    case WASM_SUSPENDER_OBJECT_TYPE:
1231    case WASM_TABLE_OBJECT_TYPE:
1232    case WASM_TAG_OBJECT_TYPE:
1233    case WASM_VALUE_OBJECT_TYPE:
1234#endif  // V8_ENABLE_WEBASSEMBLY
1235      return CALL_APPLY(JSObject);
1236#if V8_ENABLE_WEBASSEMBLY
1237    case WASM_INSTANCE_OBJECT_TYPE:
1238      return CALL_APPLY(WasmInstanceObject);
1239#endif  // V8_ENABLE_WEBASSEMBLY
1240    case JS_WEAK_MAP_TYPE:
1241    case JS_WEAK_SET_TYPE:
1242      return CALL_APPLY(JSWeakCollection);
1243    case JS_ARRAY_BUFFER_TYPE:
1244      return CALL_APPLY(JSArrayBuffer);
1245    case JS_DATA_VIEW_TYPE:
1246      return CALL_APPLY(JSDataView);
1247    case JS_TYPED_ARRAY_TYPE:
1248      return CALL_APPLY(JSTypedArray);
1249    case JS_EXTERNAL_OBJECT_TYPE:
1250      return CALL_APPLY(JSExternalObject);
1251    case WEAK_CELL_TYPE:
1252      return CALL_APPLY(WeakCell);
1253    case JS_WEAK_REF_TYPE:
1254      return CALL_APPLY(JSWeakRef);
1255    case JS_PROXY_TYPE:
1256      return CALL_APPLY(JSProxy);
1257    case FOREIGN_TYPE:
1258      return CALL_APPLY(Foreign);
1259    case MAP_TYPE:
1260      return CALL_APPLY(Map);
1261    case CODE_TYPE:
1262      return CALL_APPLY(Code);
1263    case CELL_TYPE:
1264      return CALL_APPLY(Cell);
1265    case PROPERTY_CELL_TYPE:
1266      return CALL_APPLY(PropertyCell);
1267    case SYMBOL_TYPE:
1268      return CALL_APPLY(Symbol);
1269    case BYTECODE_ARRAY_TYPE:
1270      return CALL_APPLY(BytecodeArray);
1271    case SMALL_ORDERED_HASH_SET_TYPE:
1272      return CALL_APPLY(SmallOrderedHashTable<SmallOrderedHashSet>);
1273    case SMALL_ORDERED_HASH_MAP_TYPE:
1274      return CALL_APPLY(SmallOrderedHashTable<SmallOrderedHashMap>);
1275    case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
1276      return CALL_APPLY(SmallOrderedHashTable<SmallOrderedNameDictionary>);
1277    case SWISS_NAME_DICTIONARY_TYPE:
1278      return CALL_APPLY(SwissNameDictionary);
1279    case CODE_DATA_CONTAINER_TYPE:
1280      return CALL_APPLY(CodeDataContainer);
1281    case PREPARSE_DATA_TYPE:
1282      return CALL_APPLY(PreparseData);
1283    case HEAP_NUMBER_TYPE:
1284      return CALL_APPLY(HeapNumber);
1285    case BYTE_ARRAY_TYPE:
1286      return CALL_APPLY(ByteArray);
1287    case BIGINT_TYPE:
1288      return CALL_APPLY(BigInt);
1289    case ALLOCATION_SITE_TYPE:
1290      return CALL_APPLY(AllocationSite);
1291    case ODDBALL_TYPE:
1292      return CALL_APPLY(Oddball);
1293
1294#define MAKE_STRUCT_CASE(TYPE, Name, name) \
1295  case TYPE:                               \
1296    return CALL_APPLY(Name);
1297      STRUCT_LIST(MAKE_STRUCT_CASE)
1298#undef MAKE_STRUCT_CASE
1299    case CALL_HANDLER_INFO_TYPE:
1300      return CALL_APPLY(CallHandlerInfo);
1301    case LOAD_HANDLER_TYPE:
1302      return CALL_APPLY(LoadHandler);
1303    case STORE_HANDLER_TYPE:
1304      return CALL_APPLY(StoreHandler);
1305    case SOURCE_TEXT_MODULE_TYPE:
1306      return CALL_APPLY(SourceTextModule);
1307    case SYNTHETIC_MODULE_TYPE:
1308      return CALL_APPLY(SyntheticModule);
1309// TODO(turbofan): Avoid duplicated cases when the body descriptors are
1310// identical.
1311#define MAKE_TORQUE_BODY_DESCRIPTOR_APPLY(TYPE, TypeName) \
1312  case TYPE:                                              \
1313    return CALL_APPLY(TypeName);
1314      TORQUE_INSTANCE_TYPE_TO_BODY_DESCRIPTOR_LIST(
1315          MAKE_TORQUE_BODY_DESCRIPTOR_APPLY)
1316#undef MAKE_TORQUE_BODY_DESCRIPTOR_APPLY
1317
1318    case FILLER_TYPE:
1319      return Op::template apply<FreeSpaceFillerBodyDescriptor>(
1320          std::forward<Args>(args)...);
1321
1322    case FREE_SPACE_TYPE:
1323      return CALL_APPLY(FreeSpace);
1324
1325    default:
1326      PrintF("Unknown type: %d\n", type);
1327      UNREACHABLE();
1328  }
1329#undef CALL_APPLY
1330}
1331
1332template <typename ObjectVisitor>
1333void HeapObject::IterateFast(PtrComprCageBase cage_base, ObjectVisitor* v) {
1334  v->VisitMapPointer(*this);
1335  IterateBodyFast(cage_base, v);
1336}
1337
1338template <typename ObjectVisitor>
1339void HeapObject::IterateFast(Map map, int object_size, ObjectVisitor* v) {
1340  v->VisitMapPointer(*this);
1341  IterateBodyFast(map, object_size, v);
1342}
1343
1344template <typename ObjectVisitor>
1345void HeapObject::IterateBodyFast(PtrComprCageBase cage_base, ObjectVisitor* v) {
1346  Map m = map(cage_base);
1347  IterateBodyFast(m, SizeFromMap(m), v);
1348}
1349
1350struct CallIterateBody {
1351  template <typename BodyDescriptor, typename ObjectVisitor>
1352  static void apply(Map map, HeapObject obj, int object_size,
1353                    ObjectVisitor* v) {
1354    BodyDescriptor::IterateBody(map, obj, object_size, v);
1355  }
1356};
1357
1358template <typename ObjectVisitor>
1359void HeapObject::IterateBodyFast(Map map, int object_size, ObjectVisitor* v) {
1360  BodyDescriptorApply<CallIterateBody>(map.instance_type(), map, *this,
1361                                       object_size, v);
1362}
1363
1364class EphemeronHashTable::BodyDescriptor final : public BodyDescriptorBase {
1365 public:
1366  static bool IsValidSlot(Map map, HeapObject obj, int offset) {
1367    return (offset >= EphemeronHashTable::kHeaderSize);
1368  }
1369
1370  template <typename ObjectVisitor>
1371  static inline void IterateBody(Map map, HeapObject obj, int object_size,
1372                                 ObjectVisitor* v) {
1373    int entries_start = EphemeronHashTable::kHeaderSize +
1374                        EphemeronHashTable::kElementsStartIndex * kTaggedSize;
1375    IteratePointers(obj, EphemeronHashTable::kHeaderSize, entries_start, v);
1376    EphemeronHashTable table = EphemeronHashTable::unchecked_cast(obj);
1377    for (InternalIndex i : table.IterateEntries()) {
1378      const int key_index = EphemeronHashTable::EntryToIndex(i);
1379      const int value_index = EphemeronHashTable::EntryToValueIndex(i);
1380      IterateEphemeron(obj, i.as_int(), OffsetOfElementAt(key_index),
1381                       OffsetOfElementAt(value_index), v);
1382    }
1383  }
1384
1385  static inline int SizeOf(Map map, HeapObject object) {
1386    return object.SizeFromMap(map);
1387  }
1388};
1389
1390#include "torque-generated/objects-body-descriptors-inl.inc"
1391
1392}  // namespace internal
1393}  // namespace v8
1394
1395#endif  // V8_OBJECTS_OBJECTS_BODY_DESCRIPTORS_INL_H_
1396