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_BODY_DESCRIPTORS_INL_H_
6#define V8_OBJECTS_BODY_DESCRIPTORS_INL_H_
7
8#include "src/objects-body-descriptors.h"
9
10#include <algorithm>
11
12#include "src/feedback-vector.h"
13#include "src/objects/cell.h"
14#include "src/objects/data-handler.h"
15#include "src/objects/foreign-inl.h"
16#include "src/objects/hash-table.h"
17#include "src/objects/js-collection.h"
18#include "src/objects/js-weak-refs.h"
19#include "src/objects/oddball.h"
20#include "src/objects/ordered-hash-table.h"
21#include "src/reloc-info.h"
22#include "src/transitions.h"
23#include "src/wasm/wasm-objects-inl.h"
24
25namespace v8 {
26namespace internal {
27
28template <int start_offset>
29int FlexibleBodyDescriptor<start_offset>::SizeOf(Map map, HeapObject object) {
30 return object->SizeFromMap(map);
31}
32
33template <int start_offset>
34int FlexibleWeakBodyDescriptor<start_offset>::SizeOf(Map map,
35 HeapObject object) {
36 return object->SizeFromMap(map);
37}
38
39bool BodyDescriptorBase::IsValidJSObjectSlotImpl(Map map, HeapObject obj,
40 int offset) {
41#ifdef V8_COMPRESS_POINTERS
42 STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
43 int embedder_fields_offset = JSObject::GetEmbedderFieldsStartOffset(map);
44 int inobject_fields_offset = map->GetInObjectPropertyOffset(0);
45 // |embedder_fields_offset| may be greater than |inobject_fields_offset| if
46 // the object does not have embedder fields but the check handles this
47 // case properly.
48 if (embedder_fields_offset <= offset && offset < inobject_fields_offset) {
49 // offset points to embedder fields area:
50 // [embedder_fields_offset, inobject_fields_offset).
51 STATIC_ASSERT(base::bits::IsPowerOfTwo(kEmbedderDataSlotSize));
52 return ((offset - embedder_fields_offset) & (kEmbedderDataSlotSize - 1)) ==
53 EmbedderDataSlot::kTaggedPayloadOffset;
54 }
55#else
56 // We store raw aligned pointers as Smis, so it's safe to treat the whole
57 // embedder field area as tagged slots.
58 STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
59#endif
60 if (!FLAG_unbox_double_fields || map->HasFastPointerLayout()) {
61 return true;
62 } else {
63 DCHECK(FLAG_unbox_double_fields);
64 DCHECK(IsAligned(offset, kSystemPointerSize));
65
66 LayoutDescriptorHelper helper(map);
67 DCHECK(!helper.all_fields_tagged());
68 return helper.IsTagged(offset);
69 }
70}
71
72template <typename ObjectVisitor>
73void BodyDescriptorBase::IterateJSObjectBodyImpl(Map map, HeapObject obj,
74 int start_offset,
75 int end_offset,
76 ObjectVisitor* v) {
77#ifdef V8_COMPRESS_POINTERS
78 STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
79 int header_size = JSObject::GetHeaderSize(map);
80 int inobject_fields_offset = map->GetInObjectPropertyOffset(0);
81 // We are always requested to process header and embedder fields.
82 DCHECK_LE(inobject_fields_offset, end_offset);
83 // Embedder fields are located between header and inobject properties.
84 if (header_size < inobject_fields_offset) {
85 // There are embedder fields.
86 IteratePointers(obj, start_offset, header_size, v);
87 // Iterate only tagged payload of the embedder slots and skip raw payload.
88 DCHECK_EQ(header_size, JSObject::GetEmbedderFieldsStartOffset(map));
89 for (int offset = header_size + EmbedderDataSlot::kTaggedPayloadOffset;
90 offset < inobject_fields_offset; offset += kEmbedderDataSlotSize) {
91 IteratePointer(obj, offset, v);
92 }
93 // Proceed processing inobject properties.
94 start_offset = inobject_fields_offset;
95 }
96#else
97 // We store raw aligned pointers as Smis, so it's safe to iterate the whole
98 // embedder field area as tagged slots.
99 STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
100#endif
101 if (!FLAG_unbox_double_fields || map->HasFastPointerLayout()) {
102 IteratePointers(obj, start_offset, end_offset, v);
103 } else {
104 DCHECK(FLAG_unbox_double_fields);
105 DCHECK(IsAligned(start_offset, kSystemPointerSize) &&
106 IsAligned(end_offset, kSystemPointerSize));
107
108 LayoutDescriptorHelper helper(map);
109 DCHECK(!helper.all_fields_tagged());
110 for (int offset = start_offset; offset < end_offset;) {
111 int end_of_region_offset;
112 if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) {
113 IteratePointers(obj, offset, end_of_region_offset, v);
114 }
115 offset = end_of_region_offset;
116 }
117 }
118}
119
120template <typename ObjectVisitor>
121DISABLE_CFI_PERF void BodyDescriptorBase::IteratePointers(HeapObject obj,
122 int start_offset,
123 int end_offset,
124 ObjectVisitor* v) {
125 v->VisitPointers(obj, obj.RawField(start_offset), obj.RawField(end_offset));
126}
127
128template <typename ObjectVisitor>
129void BodyDescriptorBase::IteratePointer(HeapObject obj, int offset,
130 ObjectVisitor* v) {
131 v->VisitPointer(obj, obj.RawField(offset));
132}
133
134template <typename ObjectVisitor>
135DISABLE_CFI_PERF void BodyDescriptorBase::IterateMaybeWeakPointers(
136 HeapObject obj, int start_offset, int end_offset, ObjectVisitor* v) {
137 v->VisitPointers(obj, obj.RawMaybeWeakField(start_offset),
138 obj.RawMaybeWeakField(end_offset));
139}
140
141template <typename ObjectVisitor>
142void BodyDescriptorBase::IterateMaybeWeakPointer(HeapObject obj, int offset,
143 ObjectVisitor* v) {
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 JSObject::BodyDescriptor final : public BodyDescriptorBase {
171 public:
172 static const int kStartOffset = JSReceiver::kPropertiesOrHashOffset;
173
174 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
175 if (offset < kStartOffset) return false;
176 return IsValidJSObjectSlotImpl(map, obj, offset);
177 }
178
179 template <typename ObjectVisitor>
180 static inline void IterateBody(Map map, HeapObject obj, int object_size,
181 ObjectVisitor* v) {
182 IterateJSObjectBodyImpl(map, obj, kStartOffset, object_size, v);
183 }
184
185 static inline int SizeOf(Map map, HeapObject object) {
186 return map->instance_size();
187 }
188};
189
190class JSObject::FastBodyDescriptor final : public BodyDescriptorBase {
191 public:
192 static const int kStartOffset = JSReceiver::kPropertiesOrHashOffset;
193
194 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
195 return offset >= kStartOffset;
196 }
197
198 template <typename ObjectVisitor>
199 static inline void IterateBody(Map map, HeapObject obj, int object_size,
200 ObjectVisitor* v) {
201 IteratePointers(obj, kStartOffset, object_size, v);
202 }
203
204 static inline int SizeOf(Map map, HeapObject object) {
205 return map->instance_size();
206 }
207};
208
209class WeakCell::BodyDescriptor final : public BodyDescriptorBase {
210 public:
211 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
212 return offset >= HeapObject::kHeaderSize;
213 }
214
215 template <typename ObjectVisitor>
216 static inline void IterateBody(Map map, HeapObject obj, int object_size,
217 ObjectVisitor* v) {
218 IteratePointers(obj, HeapObject::kHeaderSize, kTargetOffset, v);
219 IterateCustomWeakPointer(obj, kTargetOffset, v);
220 IteratePointers(obj, kTargetOffset + kTaggedSize, object_size, v);
221 }
222
223 static inline int SizeOf(Map map, HeapObject object) {
224 return map->instance_size();
225 }
226};
227
228class JSWeakRef::BodyDescriptor final : public BodyDescriptorBase {
229 public:
230 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
231 return IsValidJSObjectSlotImpl(map, obj, offset);
232 }
233
234 template <typename ObjectVisitor>
235 static inline void IterateBody(Map map, HeapObject obj, int object_size,
236 ObjectVisitor* v) {
237 IteratePointers(obj, JSReceiver::kPropertiesOrHashOffset, kTargetOffset, v);
238 IterateCustomWeakPointer(obj, kTargetOffset, v);
239 IterateJSObjectBodyImpl(map, obj, kTargetOffset + kTaggedSize, object_size,
240 v);
241 }
242
243 static inline int SizeOf(Map map, HeapObject object) {
244 return map->instance_size();
245 }
246};
247
248class SharedFunctionInfo::BodyDescriptor final : public BodyDescriptorBase {
249 public:
250 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
251 return FixedBodyDescriptor<kStartOfPointerFieldsOffset,
252 kEndOfTaggedFieldsOffset,
253 kAlignedSize>::IsValidSlot(map, obj, offset);
254 }
255
256 template <typename ObjectVisitor>
257 static inline void IterateBody(Map map, HeapObject obj, int object_size,
258 ObjectVisitor* v) {
259 IterateCustomWeakPointer(obj, kFunctionDataOffset, v);
260 IteratePointers(obj, SharedFunctionInfo::kStartOfStrongFieldsOffset,
261 SharedFunctionInfo::kEndOfTaggedFieldsOffset, v);
262 }
263
264 static inline int SizeOf(Map map, HeapObject object) {
265 return map->instance_size();
266 }
267};
268
269class AllocationSite::BodyDescriptor final : public BodyDescriptorBase {
270 public:
271 STATIC_ASSERT(AllocationSite::kCommonPointerFieldEndOffset ==
272 AllocationSite::kPretenureDataOffset);
273 STATIC_ASSERT(AllocationSite::kPretenureDataOffset + kInt32Size ==
274 AllocationSite::kPretenureCreateCountOffset);
275 STATIC_ASSERT(AllocationSite::kPretenureCreateCountOffset + kInt32Size ==
276 AllocationSite::kWeakNextOffset);
277
278 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
279 if (offset >= AllocationSite::kStartOffset &&
280 offset < AllocationSite::kCommonPointerFieldEndOffset) {
281 return true;
282 }
283 // check for weak_next offset
284 if (map->instance_size() == AllocationSite::kSizeWithWeakNext &&
285 offset == AllocationSite::kWeakNextOffset) {
286 return true;
287 }
288 return false;
289 }
290
291 template <typename ObjectVisitor>
292 static inline void IterateBody(Map map, HeapObject obj, int object_size,
293 ObjectVisitor* v) {
294 // Iterate over all the common pointer fields
295 IteratePointers(obj, AllocationSite::kStartOffset,
296 AllocationSite::kCommonPointerFieldEndOffset, v);
297 // Skip PretenureDataOffset and PretenureCreateCount which are Int32 fields.
298 // Visit weak_next only if it has weak_next field.
299 if (object_size == AllocationSite::kSizeWithWeakNext) {
300 IterateCustomWeakPointers(obj, AllocationSite::kWeakNextOffset,
301 AllocationSite::kSizeWithWeakNext, v);
302 }
303 }
304
305 static inline int SizeOf(Map map, HeapObject object) {
306 return map->instance_size();
307 }
308};
309
310class JSArrayBuffer::BodyDescriptor final : public BodyDescriptorBase {
311 public:
312 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
313 if (offset < kEndOfTaggedFieldsOffset) return true;
314 if (offset < kHeaderSize) return false;
315 return IsValidJSObjectSlotImpl(map, obj, offset);
316 }
317
318 template <typename ObjectVisitor>
319 static inline void IterateBody(Map map, HeapObject obj, int object_size,
320 ObjectVisitor* v) {
321 // JSArrayBuffer instances contain raw data that the GC does not know about.
322 IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v);
323 IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v);
324 }
325
326 static inline int SizeOf(Map map, HeapObject object) {
327 return map->instance_size();
328 }
329};
330
331class JSArrayBufferView::BodyDescriptor final : public BodyDescriptorBase {
332 public:
333 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
334 if (offset < kEndOfTaggedFieldsOffset) return true;
335 if (offset < kHeaderSize) return false;
336 return IsValidJSObjectSlotImpl(map, obj, offset);
337 }
338
339 template <typename ObjectVisitor>
340 static inline void IterateBody(Map map, HeapObject obj, int object_size,
341 ObjectVisitor* v) {
342 // JSArrayBufferView contains raw data that the GC does not know about.
343 IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v);
344 IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v);
345 }
346
347 static inline int SizeOf(Map map, HeapObject object) {
348 return map->instance_size();
349 }
350};
351
352template <typename Derived>
353class V8_EXPORT_PRIVATE SmallOrderedHashTable<Derived>::BodyDescriptor final
354 : public BodyDescriptorBase {
355 public:
356 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
357 Derived table = Derived::cast(obj);
358 // Only data table part contains tagged values.
359 return (offset >= DataTableStartOffset()) &&
360 (offset < table->GetBucketsStartOffset());
361 }
362
363 template <typename ObjectVisitor>
364 static inline void IterateBody(Map map, HeapObject obj, int object_size,
365 ObjectVisitor* v) {
366 Derived table = Derived::cast(obj);
367 int start_offset = DataTableStartOffset();
368 int end_offset = table->GetBucketsStartOffset();
369 IteratePointers(obj, start_offset, end_offset, v);
370 }
371
372 static inline int SizeOf(Map map, HeapObject obj) {
373 Derived table = Derived::cast(obj);
374 return table->SizeFor(table->Capacity());
375 }
376};
377
378class ByteArray::BodyDescriptor final : public BodyDescriptorBase {
379 public:
380 static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
381
382 template <typename ObjectVisitor>
383 static inline void IterateBody(Map map, HeapObject obj, int object_size,
384 ObjectVisitor* v) {}
385
386 static inline int SizeOf(Map map, HeapObject obj) {
387 return ByteArray::SizeFor(ByteArray::cast(obj)->synchronized_length());
388 }
389};
390
391class BytecodeArray::BodyDescriptor final : public BodyDescriptorBase {
392 public:
393 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
394 return offset >= kConstantPoolOffset &&
395 offset <= kSourcePositionTableOffset;
396 }
397
398 template <typename ObjectVisitor>
399 static inline void IterateBody(Map map, HeapObject obj, int object_size,
400 ObjectVisitor* v) {
401 IteratePointer(obj, kConstantPoolOffset, v);
402 IteratePointer(obj, kHandlerTableOffset, v);
403 IteratePointer(obj, kSourcePositionTableOffset, v);
404 }
405
406 static inline int SizeOf(Map map, HeapObject obj) {
407 return BytecodeArray::SizeFor(
408 BytecodeArray::cast(obj)->synchronized_length());
409 }
410};
411
412class BigInt::BodyDescriptor final : public BodyDescriptorBase {
413 public:
414 static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
415
416 template <typename ObjectVisitor>
417 static inline void IterateBody(Map map, HeapObject obj, int object_size,
418 ObjectVisitor* v) {}
419
420 static inline int SizeOf(Map map, HeapObject obj) {
421 return BigInt::SizeFor(BigInt::cast(obj)->synchronized_length());
422 }
423};
424
425class FixedDoubleArray::BodyDescriptor final : public BodyDescriptorBase {
426 public:
427 static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
428
429 template <typename ObjectVisitor>
430 static inline void IterateBody(Map map, HeapObject obj, int object_size,
431 ObjectVisitor* v) {}
432
433 static inline int SizeOf(Map map, HeapObject obj) {
434 return FixedDoubleArray::SizeFor(
435 FixedDoubleArray::cast(obj)->synchronized_length());
436 }
437};
438
439class FixedTypedArrayBase::BodyDescriptor final : public BodyDescriptorBase {
440 public:
441 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
442 return offset == kBasePointerOffset;
443 }
444
445 template <typename ObjectVisitor>
446 static inline void IterateBody(Map map, HeapObject obj, int object_size,
447 ObjectVisitor* v) {
448 IteratePointer(obj, kBasePointerOffset, v);
449 }
450
451 static inline int SizeOf(Map map, HeapObject object) {
452 return FixedTypedArrayBase::cast(object)->size();
453 }
454};
455
456class FeedbackMetadata::BodyDescriptor final : public BodyDescriptorBase {
457 public:
458 static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
459
460 template <typename ObjectVisitor>
461 static inline void IterateBody(Map map, HeapObject obj, int object_size,
462 ObjectVisitor* v) {}
463
464 static inline int SizeOf(Map map, HeapObject obj) {
465 return FeedbackMetadata::SizeFor(
466 FeedbackMetadata::cast(obj)->synchronized_slot_count());
467 }
468};
469
470class FeedbackVector::BodyDescriptor final : public BodyDescriptorBase {
471 public:
472 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
473 return offset == kSharedFunctionInfoOffset ||
474 offset == kOptimizedCodeOffset ||
475 offset == kClosureFeedbackCellArrayOffset ||
476 offset >= kFeedbackSlotsOffset;
477 }
478
479 template <typename ObjectVisitor>
480 static inline void IterateBody(Map map, HeapObject obj, int object_size,
481 ObjectVisitor* v) {
482 IteratePointer(obj, kSharedFunctionInfoOffset, v);
483 IterateMaybeWeakPointer(obj, kOptimizedCodeOffset, v);
484 IteratePointer(obj, kClosureFeedbackCellArrayOffset, v);
485 IterateMaybeWeakPointers(obj, kFeedbackSlotsOffset, object_size, v);
486 }
487
488 static inline int SizeOf(Map map, HeapObject obj) {
489 return FeedbackVector::SizeFor(FeedbackVector::cast(obj)->length());
490 }
491};
492
493class PreparseData::BodyDescriptor final : public BodyDescriptorBase {
494 public:
495 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
496 return offset >= PreparseData::cast(obj)->inner_start_offset();
497 }
498
499 template <typename ObjectVisitor>
500 static inline void IterateBody(Map map, HeapObject obj, int object_size,
501 ObjectVisitor* v) {
502 PreparseData data = PreparseData::cast(obj);
503 int start_offset = data->inner_start_offset();
504 int end_offset = start_offset + data->children_length() * kTaggedSize;
505 IteratePointers(obj, start_offset, end_offset, v);
506 }
507
508 static inline int SizeOf(Map map, HeapObject obj) {
509 PreparseData data = PreparseData::cast(obj);
510 return PreparseData::SizeFor(data->data_length(), data->children_length());
511 }
512};
513
514class PrototypeInfo::BodyDescriptor final : public BodyDescriptorBase {
515 public:
516 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
517 return offset >= HeapObject::kHeaderSize;
518 }
519
520 template <typename ObjectVisitor>
521 static inline void IterateBody(Map map, HeapObject obj, int object_size,
522 ObjectVisitor* v) {
523 IteratePointers(obj, HeapObject::kHeaderSize, kObjectCreateMapOffset, v);
524 IterateMaybeWeakPointer(obj, kObjectCreateMapOffset, v);
525 IteratePointers(obj, kObjectCreateMapOffset + kTaggedSize, object_size, v);
526 }
527
528 static inline int SizeOf(Map map, HeapObject obj) {
529 return obj->SizeFromMap(map);
530 }
531};
532
533class JSWeakCollection::BodyDescriptorImpl final : public BodyDescriptorBase {
534 public:
535 STATIC_ASSERT(kTableOffset + kTaggedSize == kSize);
536
537 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
538 return IsValidJSObjectSlotImpl(map, obj, offset);
539 }
540
541 template <typename ObjectVisitor>
542 static inline void IterateBody(Map map, HeapObject obj, int object_size,
543 ObjectVisitor* v) {
544 IterateJSObjectBodyImpl(map, obj, kPropertiesOrHashOffset, object_size, v);
545 }
546
547 static inline int SizeOf(Map map, HeapObject object) {
548 return map->instance_size();
549 }
550};
551
552class Foreign::BodyDescriptor final : public BodyDescriptorBase {
553 public:
554 static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
555
556 template <typename ObjectVisitor>
557 static inline void IterateBody(Map map, HeapObject obj, int object_size,
558 ObjectVisitor* v) {
559 v->VisitExternalReference(
560 Foreign::cast(obj), reinterpret_cast<Address*>(
561 obj.RawField(kForeignAddressOffset).address()));
562 }
563
564 static inline int SizeOf(Map map, HeapObject object) { return kSize; }
565};
566
567class ExternalOneByteString::BodyDescriptor final : public BodyDescriptorBase {
568 public:
569 static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
570
571 template <typename ObjectVisitor>
572 static inline void IterateBody(Map map, HeapObject obj, int object_size,
573 ObjectVisitor* v) {}
574
575 static inline int SizeOf(Map map, HeapObject object) { return kSize; }
576};
577
578class ExternalTwoByteString::BodyDescriptor final : public BodyDescriptorBase {
579 public:
580 static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
581
582 template <typename ObjectVisitor>
583 static inline void IterateBody(Map map, HeapObject obj, int object_size,
584 ObjectVisitor* v) {}
585
586 static inline int SizeOf(Map map, HeapObject object) { return kSize; }
587};
588
589class Code::BodyDescriptor final : public BodyDescriptorBase {
590 public:
591 STATIC_ASSERT(kRelocationInfoOffset + kTaggedSize ==
592 kDeoptimizationDataOffset);
593 STATIC_ASSERT(kDeoptimizationDataOffset + kTaggedSize ==
594 kSourcePositionTableOffset);
595 STATIC_ASSERT(kSourcePositionTableOffset + kTaggedSize ==
596 kCodeDataContainerOffset);
597 STATIC_ASSERT(kCodeDataContainerOffset + kTaggedSize == kDataStart);
598
599 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
600 // Slots in code can't be invalid because we never trim code objects.
601 return true;
602 }
603
604 static constexpr int kRelocModeMask =
605 RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
606 RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
607 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
608 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
609 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
610 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
611 RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) |
612 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
613
614 template <typename ObjectVisitor>
615 static inline void IterateBody(Map map, HeapObject obj, ObjectVisitor* v) {
616 // GC does not visit data/code in the header and in the body directly.
617 IteratePointers(obj, kRelocationInfoOffset, kDataStart, v);
618
619 RelocIterator it(Code::cast(obj), kRelocModeMask);
620 v->VisitRelocInfo(&it);
621 }
622
623 template <typename ObjectVisitor>
624 static inline void IterateBody(Map map, HeapObject obj, int object_size,
625 ObjectVisitor* v) {
626 IterateBody(map, obj, v);
627 }
628
629 static inline int SizeOf(Map map, HeapObject object) {
630 return Code::unchecked_cast(object)->CodeSize();
631 }
632};
633
634class SeqOneByteString::BodyDescriptor final : public BodyDescriptorBase {
635 public:
636 static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
637
638 template <typename ObjectVisitor>
639 static inline void IterateBody(Map map, HeapObject obj, int object_size,
640 ObjectVisitor* v) {}
641
642 static inline int SizeOf(Map map, HeapObject obj) {
643 SeqOneByteString string = SeqOneByteString::cast(obj);
644 return string->SizeFor(string->synchronized_length());
645 }
646};
647
648class SeqTwoByteString::BodyDescriptor final : public BodyDescriptorBase {
649 public:
650 static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
651
652 template <typename ObjectVisitor>
653 static inline void IterateBody(Map map, HeapObject obj, int object_size,
654 ObjectVisitor* v) {}
655
656 static inline int SizeOf(Map map, HeapObject obj) {
657 SeqTwoByteString string = SeqTwoByteString::cast(obj);
658 return string->SizeFor(string->synchronized_length());
659 }
660};
661
662class WasmInstanceObject::BodyDescriptor final : public BodyDescriptorBase {
663 public:
664 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
665 SLOW_DCHECK(std::is_sorted(std::begin(kTaggedFieldOffsets),
666 std::end(kTaggedFieldOffsets)));
667 STATIC_ASSERT(sizeof(*kTaggedFieldOffsets) == sizeof(uint16_t));
668 if (offset < int{8 * sizeof(*kTaggedFieldOffsets)} &&
669 std::binary_search(std::begin(kTaggedFieldOffsets),
670 std::end(kTaggedFieldOffsets),
671 static_cast<uint16_t>(offset))) {
672 return true;
673 }
674 return IsValidJSObjectSlotImpl(map, obj, offset);
675 }
676
677 template <typename ObjectVisitor>
678 static inline void IterateBody(Map map, HeapObject obj, int object_size,
679 ObjectVisitor* v) {
680 IteratePointers(obj, kPropertiesOrHashOffset, JSObject::kHeaderSize, v);
681 for (uint16_t offset : kTaggedFieldOffsets) {
682 IteratePointer(obj, offset, v);
683 }
684 IterateJSObjectBodyImpl(map, obj, kSize, object_size, v);
685 }
686
687 static inline int SizeOf(Map map, HeapObject object) {
688 return map->instance_size();
689 }
690};
691
692class Map::BodyDescriptor final : public BodyDescriptorBase {
693 public:
694 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
695 return offset >= Map::kPointerFieldsBeginOffset &&
696 offset < Map::kPointerFieldsEndOffset;
697 }
698
699 template <typename ObjectVisitor>
700 static inline void IterateBody(Map map, HeapObject obj, int object_size,
701 ObjectVisitor* v) {
702 IteratePointers(obj, Map::kPointerFieldsBeginOffset,
703 Map::kTransitionsOrPrototypeInfoOffset, v);
704 IterateMaybeWeakPointer(obj, kTransitionsOrPrototypeInfoOffset, v);
705 IteratePointers(obj, Map::kTransitionsOrPrototypeInfoOffset + kTaggedSize,
706 Map::kPointerFieldsEndOffset, v);
707 }
708
709 static inline int SizeOf(Map map, HeapObject obj) { return Map::kSize; }
710};
711
712class DataHandler::BodyDescriptor final : public BodyDescriptorBase {
713 public:
714 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
715 return offset >= HeapObject::kHeaderSize;
716 }
717
718 template <typename ObjectVisitor>
719 static inline void IterateBody(Map map, HeapObject obj, int object_size,
720 ObjectVisitor* v) {
721 static_assert(kSmiHandlerOffset < kData1Offset,
722 "Field order must be in sync with this iteration code");
723 static_assert(kData1Offset < kSizeWithData1,
724 "Field order must be in sync with this iteration code");
725 IteratePointers(obj, kSmiHandlerOffset, kData1Offset, v);
726 IterateMaybeWeakPointers(obj, kData1Offset, object_size, v);
727 }
728
729 static inline int SizeOf(Map map, HeapObject object) {
730 return object->SizeFromMap(map);
731 }
732};
733
734class NativeContext::BodyDescriptor final : public BodyDescriptorBase {
735 public:
736 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
737 return offset < NativeContext::kEndOfTaggedFieldsOffset;
738 }
739
740 template <typename ObjectVisitor>
741 static inline void IterateBody(Map map, HeapObject obj, int object_size,
742 ObjectVisitor* v) {
743 IteratePointers(obj, NativeContext::kStartOfStrongFieldsOffset,
744 NativeContext::kEndOfStrongFieldsOffset, v);
745 IterateCustomWeakPointers(obj, NativeContext::kStartOfWeakFieldsOffset,
746 NativeContext::kEndOfWeakFieldsOffset, v);
747 }
748
749 static inline int SizeOf(Map map, HeapObject object) {
750 return NativeContext::kSize;
751 }
752};
753
754class CodeDataContainer::BodyDescriptor final : public BodyDescriptorBase {
755 public:
756 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
757 return offset >= CodeDataContainer::kHeaderSize &&
758 offset < CodeDataContainer::kSize;
759 }
760
761 template <typename ObjectVisitor>
762 static inline void IterateBody(Map map, HeapObject obj, int object_size,
763 ObjectVisitor* v) {
764 IteratePointers(obj, CodeDataContainer::kHeaderSize,
765 CodeDataContainer::kPointerFieldsStrongEndOffset, v);
766 IterateCustomWeakPointers(
767 obj, CodeDataContainer::kPointerFieldsStrongEndOffset,
768 CodeDataContainer::kPointerFieldsWeakEndOffset, v);
769 }
770
771 static inline int SizeOf(Map map, HeapObject object) {
772 return CodeDataContainer::kSize;
773 }
774};
775
776class EmbedderDataArray::BodyDescriptor final : public BodyDescriptorBase {
777 public:
778 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
779#ifdef V8_COMPRESS_POINTERS
780 STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
781 STATIC_ASSERT(base::bits::IsPowerOfTwo(kEmbedderDataSlotSize));
782 return (offset < EmbedderDataArray::kHeaderSize) ||
783 (((offset - EmbedderDataArray::kHeaderSize) &
784 (kEmbedderDataSlotSize - 1)) ==
785 EmbedderDataSlot::kTaggedPayloadOffset);
786#else
787 STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
788 // We store raw aligned pointers as Smis, so it's safe to iterate the whole
789 // array.
790 return true;
791#endif
792 }
793
794 template <typename ObjectVisitor>
795 static inline void IterateBody(Map map, HeapObject obj, int object_size,
796 ObjectVisitor* v) {
797#ifdef V8_COMPRESS_POINTERS
798 STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
799 // Iterate only tagged payload of the embedder slots and skip raw payload.
800 for (int offset = EmbedderDataArray::OffsetOfElementAt(0) +
801 EmbedderDataSlot::kTaggedPayloadOffset;
802 offset < object_size; offset += kEmbedderDataSlotSize) {
803 IteratePointer(obj, offset, v);
804 }
805#else
806 // We store raw aligned pointers as Smis, so it's safe to iterate the whole
807 // array.
808 STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
809 IteratePointers(obj, EmbedderDataArray::kHeaderSize, object_size, v);
810#endif
811 }
812
813 static inline int SizeOf(Map map, HeapObject object) {
814 return object->SizeFromMap(map);
815 }
816};
817
818template <typename Op, typename ReturnType, typename T1, typename T2,
819 typename T3, typename T4>
820ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
821 if (type < FIRST_NONSTRING_TYPE) {
822 switch (type & kStringRepresentationMask) {
823 case kSeqStringTag:
824 return ReturnType();
825 case kConsStringTag:
826 return Op::template apply<ConsString::BodyDescriptor>(p1, p2, p3, p4);
827 case kThinStringTag:
828 return Op::template apply<ThinString::BodyDescriptor>(p1, p2, p3, p4);
829 case kSlicedStringTag:
830 return Op::template apply<SlicedString::BodyDescriptor>(p1, p2, p3, p4);
831 case kExternalStringTag:
832 if ((type & kStringEncodingMask) == kOneByteStringTag) {
833 return Op::template apply<ExternalOneByteString::BodyDescriptor>(
834 p1, p2, p3, p4);
835 } else {
836 return Op::template apply<ExternalTwoByteString::BodyDescriptor>(
837 p1, p2, p3, p4);
838 }
839 }
840 UNREACHABLE();
841 }
842
843 switch (type) {
844 case EMBEDDER_DATA_ARRAY_TYPE:
845 return Op::template apply<EmbedderDataArray::BodyDescriptor>(p1, p2, p3,
846 p4);
847 case FIXED_ARRAY_TYPE:
848 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
849 case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE:
850 case HASH_TABLE_TYPE:
851 case ORDERED_HASH_MAP_TYPE:
852 case ORDERED_HASH_SET_TYPE:
853 case ORDERED_NAME_DICTIONARY_TYPE:
854 case NAME_DICTIONARY_TYPE:
855 case GLOBAL_DICTIONARY_TYPE:
856 case NUMBER_DICTIONARY_TYPE:
857 case SIMPLE_NUMBER_DICTIONARY_TYPE:
858 case STRING_TABLE_TYPE:
859 case SCOPE_INFO_TYPE:
860 case SCRIPT_CONTEXT_TABLE_TYPE:
861 return Op::template apply<FixedArray::BodyDescriptor>(p1, p2, p3, p4);
862 case EPHEMERON_HASH_TABLE_TYPE:
863 return Op::template apply<EphemeronHashTable::BodyDescriptor>(p1, p2, p3,
864 p4);
865 case AWAIT_CONTEXT_TYPE:
866 case BLOCK_CONTEXT_TYPE:
867 case CATCH_CONTEXT_TYPE:
868 case DEBUG_EVALUATE_CONTEXT_TYPE:
869 case EVAL_CONTEXT_TYPE:
870 case FUNCTION_CONTEXT_TYPE:
871 case MODULE_CONTEXT_TYPE:
872 case SCRIPT_CONTEXT_TYPE:
873 case WITH_CONTEXT_TYPE:
874 return Op::template apply<Context::BodyDescriptor>(p1, p2, p3, p4);
875 case NATIVE_CONTEXT_TYPE:
876 return Op::template apply<NativeContext::BodyDescriptor>(p1, p2, p3, p4);
877 case WEAK_FIXED_ARRAY_TYPE:
878 return Op::template apply<WeakFixedArray::BodyDescriptor>(p1, p2, p3, p4);
879 case WEAK_ARRAY_LIST_TYPE:
880 return Op::template apply<WeakArrayList::BodyDescriptor>(p1, p2, p3, p4);
881 case FIXED_DOUBLE_ARRAY_TYPE:
882 return ReturnType();
883 case FEEDBACK_METADATA_TYPE:
884 return Op::template apply<FeedbackMetadata::BodyDescriptor>(p1, p2, p3,
885 p4);
886 case PROPERTY_ARRAY_TYPE:
887 return Op::template apply<PropertyArray::BodyDescriptor>(p1, p2, p3, p4);
888 case DESCRIPTOR_ARRAY_TYPE:
889 return Op::template apply<DescriptorArray::BodyDescriptor>(p1, p2, p3,
890 p4);
891 case TRANSITION_ARRAY_TYPE:
892 return Op::template apply<TransitionArray::BodyDescriptor>(p1, p2, p3,
893 p4);
894 case FEEDBACK_CELL_TYPE:
895 return Op::template apply<FeedbackCell::BodyDescriptor>(p1, p2, p3, p4);
896 case FEEDBACK_VECTOR_TYPE:
897 return Op::template apply<FeedbackVector::BodyDescriptor>(p1, p2, p3, p4);
898 case JS_OBJECT_TYPE:
899 case JS_ERROR_TYPE:
900 case JS_ARGUMENTS_TYPE:
901 case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
902 case JS_PROMISE_TYPE:
903 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
904 case JS_GENERATOR_OBJECT_TYPE:
905 case JS_ASYNC_FUNCTION_OBJECT_TYPE:
906 case JS_ASYNC_GENERATOR_OBJECT_TYPE:
907 case JS_VALUE_TYPE:
908 case JS_DATE_TYPE:
909 case JS_ARRAY_TYPE:
910 case JS_ARRAY_ITERATOR_TYPE:
911 case JS_MODULE_NAMESPACE_TYPE:
912 case JS_SET_TYPE:
913 case JS_MAP_TYPE:
914 case JS_SET_KEY_VALUE_ITERATOR_TYPE:
915 case JS_SET_VALUE_ITERATOR_TYPE:
916 case JS_MAP_KEY_ITERATOR_TYPE:
917 case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
918 case JS_MAP_VALUE_ITERATOR_TYPE:
919 case JS_STRING_ITERATOR_TYPE:
920 case JS_REGEXP_STRING_ITERATOR_TYPE:
921 case JS_REGEXP_TYPE:
922 case JS_GLOBAL_PROXY_TYPE:
923 case JS_GLOBAL_OBJECT_TYPE:
924 case JS_API_OBJECT_TYPE:
925 case JS_SPECIAL_API_OBJECT_TYPE:
926 case JS_MESSAGE_OBJECT_TYPE:
927 case JS_BOUND_FUNCTION_TYPE:
928 case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE:
929 case JS_FINALIZATION_GROUP_TYPE:
930#ifdef V8_INTL_SUPPORT
931 case JS_INTL_V8_BREAK_ITERATOR_TYPE:
932 case JS_INTL_COLLATOR_TYPE:
933 case JS_INTL_DATE_TIME_FORMAT_TYPE:
934 case JS_INTL_LIST_FORMAT_TYPE:
935 case JS_INTL_LOCALE_TYPE:
936 case JS_INTL_NUMBER_FORMAT_TYPE:
937 case JS_INTL_PLURAL_RULES_TYPE:
938 case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
939 case JS_INTL_SEGMENT_ITERATOR_TYPE:
940 case JS_INTL_SEGMENTER_TYPE:
941#endif // V8_INTL_SUPPORT
942 case WASM_EXCEPTION_TYPE:
943 case WASM_GLOBAL_TYPE:
944 case WASM_MEMORY_TYPE:
945 case WASM_MODULE_TYPE:
946 case WASM_TABLE_TYPE:
947 return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3, p4);
948 case WASM_INSTANCE_TYPE:
949 return Op::template apply<WasmInstanceObject::BodyDescriptor>(p1, p2, p3,
950 p4);
951 case JS_WEAK_MAP_TYPE:
952 case JS_WEAK_SET_TYPE:
953 return Op::template apply<JSWeakCollection::BodyDescriptor>(p1, p2, p3,
954 p4);
955 case JS_ARRAY_BUFFER_TYPE:
956 return Op::template apply<JSArrayBuffer::BodyDescriptor>(p1, p2, p3, p4);
957 case JS_DATA_VIEW_TYPE:
958 return Op::template apply<JSDataView::BodyDescriptor>(p1, p2, p3, p4);
959 case JS_TYPED_ARRAY_TYPE:
960 return Op::template apply<JSTypedArray::BodyDescriptor>(p1, p2, p3, p4);
961 case JS_FUNCTION_TYPE:
962 return Op::template apply<JSFunction::BodyDescriptor>(p1, p2, p3, p4);
963 case WEAK_CELL_TYPE:
964 return Op::template apply<WeakCell::BodyDescriptor>(p1, p2, p3, p4);
965 case JS_WEAK_REF_TYPE:
966 return Op::template apply<JSWeakRef::BodyDescriptor>(p1, p2, p3, p4);
967 case ODDBALL_TYPE:
968 return Op::template apply<Oddball::BodyDescriptor>(p1, p2, p3, p4);
969 case JS_PROXY_TYPE:
970 return Op::template apply<JSProxy::BodyDescriptor>(p1, p2, p3, p4);
971 case FOREIGN_TYPE:
972 return Op::template apply<Foreign::BodyDescriptor>(p1, p2, p3, p4);
973 case MAP_TYPE:
974 return Op::template apply<Map::BodyDescriptor>(p1, p2, p3, p4);
975 case CODE_TYPE:
976 return Op::template apply<Code::BodyDescriptor>(p1, p2, p3, p4);
977 case CELL_TYPE:
978 return Op::template apply<Cell::BodyDescriptor>(p1, p2, p3, p4);
979 case PROPERTY_CELL_TYPE:
980 return Op::template apply<PropertyCell::BodyDescriptor>(p1, p2, p3, p4);
981 case SYMBOL_TYPE:
982 return Op::template apply<Symbol::BodyDescriptor>(p1, p2, p3, p4);
983 case BYTECODE_ARRAY_TYPE:
984 return Op::template apply<BytecodeArray::BodyDescriptor>(p1, p2, p3, p4);
985 case SMALL_ORDERED_HASH_SET_TYPE:
986 return Op::template apply<
987 SmallOrderedHashTable<SmallOrderedHashSet>::BodyDescriptor>(p1, p2,
988 p3, p4);
989 case SMALL_ORDERED_HASH_MAP_TYPE:
990 return Op::template apply<
991 SmallOrderedHashTable<SmallOrderedHashMap>::BodyDescriptor>(p1, p2,
992 p3, p4);
993 case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
994 return Op::template apply<
995 SmallOrderedHashTable<SmallOrderedNameDictionary>::BodyDescriptor>(
996 p1, p2, p3, p4);
997 case CODE_DATA_CONTAINER_TYPE:
998 return Op::template apply<CodeDataContainer::BodyDescriptor>(p1, p2, p3,
999 p4);
1000 case PREPARSE_DATA_TYPE:
1001 return Op::template apply<PreparseData::BodyDescriptor>(p1, p2, p3, p4);
1002 case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE:
1003 return Op::template apply<
1004 UncompiledDataWithoutPreparseData::BodyDescriptor>(p1, p2, p3, p4);
1005 case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE:
1006 return Op::template apply<UncompiledDataWithPreparseData::BodyDescriptor>(
1007 p1, p2, p3, p4);
1008 case HEAP_NUMBER_TYPE:
1009 case MUTABLE_HEAP_NUMBER_TYPE:
1010 case FILLER_TYPE:
1011 case BYTE_ARRAY_TYPE:
1012 case FREE_SPACE_TYPE:
1013 case BIGINT_TYPE:
1014 return ReturnType();
1015
1016#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \
1017 case FIXED_##TYPE##_ARRAY_TYPE: \
1018 return Op::template apply<FixedTypedArrayBase::BodyDescriptor>(p1, p2, p3, \
1019 p4);
1020 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1021#undef TYPED_ARRAY_CASE
1022
1023 case SHARED_FUNCTION_INFO_TYPE: {
1024 return Op::template apply<SharedFunctionInfo::BodyDescriptor>(p1, p2, p3,
1025 p4);
1026 }
1027 case ALLOCATION_SITE_TYPE:
1028 return Op::template apply<AllocationSite::BodyDescriptor>(p1, p2, p3, p4);
1029
1030#define MAKE_STRUCT_CASE(TYPE, Name, name) case TYPE:
1031 STRUCT_LIST(MAKE_STRUCT_CASE)
1032#undef MAKE_STRUCT_CASE
1033 if (type == PROTOTYPE_INFO_TYPE) {
1034 return Op::template apply<PrototypeInfo::BodyDescriptor>(p1, p2, p3,
1035 p4);
1036 } else {
1037 return Op::template apply<StructBodyDescriptor>(p1, p2, p3, p4);
1038 }
1039 case CALL_HANDLER_INFO_TYPE:
1040 return Op::template apply<StructBodyDescriptor>(p1, p2, p3, p4);
1041 case LOAD_HANDLER_TYPE:
1042 case STORE_HANDLER_TYPE:
1043 return Op::template apply<DataHandler::BodyDescriptor>(p1, p2, p3, p4);
1044 default:
1045 PrintF("Unknown type: %d\n", type);
1046 UNREACHABLE();
1047 }
1048}
1049
1050
1051template <typename ObjectVisitor>
1052void HeapObject::IterateFast(ObjectVisitor* v) {
1053 BodyDescriptorBase::IteratePointer(*this, kMapOffset, v);
1054 IterateBodyFast(v);
1055}
1056
1057
1058template <typename ObjectVisitor>
1059void HeapObject::IterateBodyFast(ObjectVisitor* v) {
1060 Map m = map();
1061 IterateBodyFast(m, SizeFromMap(m), v);
1062}
1063
1064
1065struct CallIterateBody {
1066 template <typename BodyDescriptor, typename ObjectVisitor>
1067 static void apply(Map map, HeapObject obj, int object_size,
1068 ObjectVisitor* v) {
1069 BodyDescriptor::IterateBody(map, obj, object_size, v);
1070 }
1071};
1072
1073template <typename ObjectVisitor>
1074void HeapObject::IterateBodyFast(Map map, int object_size, ObjectVisitor* v) {
1075 BodyDescriptorApply<CallIterateBody, void>(map->instance_type(), map, *this,
1076 object_size, v);
1077}
1078
1079class EphemeronHashTable::BodyDescriptor final : public BodyDescriptorBase {
1080 public:
1081 static bool IsValidSlot(Map map, HeapObject obj, int offset) {
1082 return (offset >= EphemeronHashTable::kHeaderSize);
1083 }
1084
1085 template <typename ObjectVisitor>
1086 static inline void IterateBody(Map map, HeapObject obj, int object_size,
1087 ObjectVisitor* v) {
1088 int entries_start = EphemeronHashTable::kHeaderSize +
1089 EphemeronHashTable::kElementsStartIndex * kTaggedSize;
1090 IteratePointers(obj, EphemeronHashTable::kHeaderSize, entries_start, v);
1091 EphemeronHashTable table = EphemeronHashTable::unchecked_cast(obj);
1092 int entries = table.Capacity();
1093 for (int i = 0; i < entries; ++i) {
1094 const int key_index = EphemeronHashTable::EntryToIndex(i);
1095 const int value_index = EphemeronHashTable::EntryToValueIndex(i);
1096 IterateEphemeron(obj, i, OffsetOfElementAt(key_index),
1097 OffsetOfElementAt(value_index), v);
1098 }
1099 }
1100
1101 static inline int SizeOf(Map map, HeapObject object) {
1102 return object->SizeFromMap(map);
1103 }
1104};
1105
1106} // namespace internal
1107} // namespace v8
1108
1109#endif // V8_OBJECTS_BODY_DESCRIPTORS_INL_H_
1110