summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects/objects-body-descriptors-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects/objects-body-descriptors-inl.h')
-rw-r--r--deps/v8/src/objects/objects-body-descriptors-inl.h1116
1 files changed, 1116 insertions, 0 deletions
diff --git a/deps/v8/src/objects/objects-body-descriptors-inl.h b/deps/v8/src/objects/objects-body-descriptors-inl.h
new file mode 100644
index 0000000000..8626165647
--- /dev/null
+++ b/deps/v8/src/objects/objects-body-descriptors-inl.h
@@ -0,0 +1,1116 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_OBJECTS_OBJECTS_BODY_DESCRIPTORS_INL_H_
+#define V8_OBJECTS_OBJECTS_BODY_DESCRIPTORS_INL_H_
+
+#include "src/objects/objects-body-descriptors.h"
+
+#include <algorithm>
+
+#include "src/codegen/reloc-info.h"
+#include "src/objects/cell.h"
+#include "src/objects/data-handler.h"
+#include "src/objects/feedback-vector.h"
+#include "src/objects/foreign-inl.h"
+#include "src/objects/hash-table.h"
+#include "src/objects/js-collection.h"
+#include "src/objects/js-weak-refs.h"
+#include "src/objects/oddball.h"
+#include "src/objects/ordered-hash-table.h"
+#include "src/objects/transitions.h"
+#include "src/wasm/wasm-objects-inl.h"
+
+namespace v8 {
+namespace internal {
+
+template <int start_offset>
+int FlexibleBodyDescriptor<start_offset>::SizeOf(Map map, HeapObject object) {
+ return object.SizeFromMap(map);
+}
+
+template <int start_offset>
+int FlexibleWeakBodyDescriptor<start_offset>::SizeOf(Map map,
+ HeapObject object) {
+ return object.SizeFromMap(map);
+}
+
+bool BodyDescriptorBase::IsValidJSObjectSlotImpl(Map map, HeapObject obj,
+ int offset) {
+#ifdef V8_COMPRESS_POINTERS
+ STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
+ int embedder_fields_offset = JSObject::GetEmbedderFieldsStartOffset(map);
+ int inobject_fields_offset = map.GetInObjectPropertyOffset(0);
+ // |embedder_fields_offset| may be greater than |inobject_fields_offset| if
+ // the object does not have embedder fields but the check handles this
+ // case properly.
+ if (embedder_fields_offset <= offset && offset < inobject_fields_offset) {
+ // offset points to embedder fields area:
+ // [embedder_fields_offset, inobject_fields_offset).
+ STATIC_ASSERT(base::bits::IsPowerOfTwo(kEmbedderDataSlotSize));
+ return ((offset - embedder_fields_offset) & (kEmbedderDataSlotSize - 1)) ==
+ EmbedderDataSlot::kTaggedPayloadOffset;
+ }
+#else
+ // We store raw aligned pointers as Smis, so it's safe to treat the whole
+ // embedder field area as tagged slots.
+ STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
+#endif
+ if (!FLAG_unbox_double_fields || map.HasFastPointerLayout()) {
+ return true;
+ } else {
+ DCHECK(FLAG_unbox_double_fields);
+ DCHECK(IsAligned(offset, kSystemPointerSize));
+
+ LayoutDescriptorHelper helper(map);
+ DCHECK(!helper.all_fields_tagged());
+ return helper.IsTagged(offset);
+ }
+}
+
+template <typename ObjectVisitor>
+void BodyDescriptorBase::IterateJSObjectBodyImpl(Map map, HeapObject obj,
+ int start_offset,
+ int end_offset,
+ ObjectVisitor* v) {
+#ifdef V8_COMPRESS_POINTERS
+ STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
+ int header_size = JSObject::GetHeaderSize(map);
+ int inobject_fields_offset = map.GetInObjectPropertyOffset(0);
+ // We are always requested to process header and embedder fields.
+ DCHECK_LE(inobject_fields_offset, end_offset);
+ // Embedder fields are located between header and inobject properties.
+ if (header_size < inobject_fields_offset) {
+ // There are embedder fields.
+ IteratePointers(obj, start_offset, header_size, v);
+ // Iterate only tagged payload of the embedder slots and skip raw payload.
+ DCHECK_EQ(header_size, JSObject::GetEmbedderFieldsStartOffset(map));
+ for (int offset = header_size + EmbedderDataSlot::kTaggedPayloadOffset;
+ offset < inobject_fields_offset; offset += kEmbedderDataSlotSize) {
+ IteratePointer(obj, offset, v);
+ }
+ // Proceed processing inobject properties.
+ start_offset = inobject_fields_offset;
+ }
+#else
+ // We store raw aligned pointers as Smis, so it's safe to iterate the whole
+ // embedder field area as tagged slots.
+ STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
+#endif
+ if (!FLAG_unbox_double_fields || map.HasFastPointerLayout()) {
+ IteratePointers(obj, start_offset, end_offset, v);
+ } else {
+ DCHECK(FLAG_unbox_double_fields);
+ DCHECK(IsAligned(start_offset, kSystemPointerSize) &&
+ IsAligned(end_offset, kSystemPointerSize));
+
+ LayoutDescriptorHelper helper(map);
+ DCHECK(!helper.all_fields_tagged());
+ for (int offset = start_offset; offset < end_offset;) {
+ int end_of_region_offset;
+ if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) {
+ IteratePointers(obj, offset, end_of_region_offset, v);
+ }
+ offset = end_of_region_offset;
+ }
+ }
+}
+
+template <typename ObjectVisitor>
+DISABLE_CFI_PERF void BodyDescriptorBase::IteratePointers(HeapObject obj,
+ int start_offset,
+ int end_offset,
+ ObjectVisitor* v) {
+ v->VisitPointers(obj, obj.RawField(start_offset), obj.RawField(end_offset));
+}
+
+template <typename ObjectVisitor>
+void BodyDescriptorBase::IteratePointer(HeapObject obj, int offset,
+ ObjectVisitor* v) {
+ v->VisitPointer(obj, obj.RawField(offset));
+}
+
+template <typename ObjectVisitor>
+DISABLE_CFI_PERF void BodyDescriptorBase::IterateMaybeWeakPointers(
+ HeapObject obj, int start_offset, int end_offset, ObjectVisitor* v) {
+ v->VisitPointers(obj, obj.RawMaybeWeakField(start_offset),
+ obj.RawMaybeWeakField(end_offset));
+}
+
+template <typename ObjectVisitor>
+void BodyDescriptorBase::IterateMaybeWeakPointer(HeapObject obj, int offset,
+ ObjectVisitor* v) {
+ v->VisitPointer(obj, obj.RawMaybeWeakField(offset));
+}
+
+template <typename ObjectVisitor>
+DISABLE_CFI_PERF void BodyDescriptorBase::IterateCustomWeakPointers(
+ HeapObject obj, int start_offset, int end_offset, ObjectVisitor* v) {
+ v->VisitCustomWeakPointers(obj, obj.RawField(start_offset),
+ obj.RawField(end_offset));
+}
+
+template <typename ObjectVisitor>
+DISABLE_CFI_PERF void BodyDescriptorBase::IterateEphemeron(HeapObject obj,
+ int index,
+ int key_offset,
+ int value_offset,
+ ObjectVisitor* v) {
+ v->VisitEphemeron(obj, index, obj.RawField(key_offset),
+ obj.RawField(value_offset));
+}
+
+template <typename ObjectVisitor>
+void BodyDescriptorBase::IterateCustomWeakPointer(HeapObject obj, int offset,
+ ObjectVisitor* v) {
+ v->VisitCustomWeakPointer(obj, obj.RawField(offset));
+}
+
+class JSObject::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static const int kStartOffset = JSReceiver::kPropertiesOrHashOffset;
+
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ if (offset < kStartOffset) return false;
+ return IsValidJSObjectSlotImpl(map, obj, offset);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IterateJSObjectBodyImpl(map, obj, kStartOffset, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class JSObject::FastBodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static const int kStartOffset = JSReceiver::kPropertiesOrHashOffset;
+
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return offset >= kStartOffset;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointers(obj, kStartOffset, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class WeakCell::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return offset >= HeapObject::kHeaderSize;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointers(obj, HeapObject::kHeaderSize, kTargetOffset, v);
+ IterateCustomWeakPointer(obj, kTargetOffset, v);
+ IteratePointers(obj, kTargetOffset + kTaggedSize, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class JSWeakRef::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return IsValidJSObjectSlotImpl(map, obj, offset);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointers(obj, JSReceiver::kPropertiesOrHashOffset, kTargetOffset, v);
+ IterateCustomWeakPointer(obj, kTargetOffset, v);
+ IterateJSObjectBodyImpl(map, obj, kTargetOffset + kTaggedSize, object_size,
+ v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class SharedFunctionInfo::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ static_assert(kEndOfWeakFieldsOffset == kStartOfStrongFieldsOffset,
+ "Leverage that strong fields directly follow weak fields"
+ "to call FixedBodyDescriptor<...>::IsValidSlot below");
+ return FixedBodyDescriptor<kStartOfWeakFieldsOffset,
+ kEndOfStrongFieldsOffset,
+ kAlignedSize>::IsValidSlot(map, obj, offset);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IterateCustomWeakPointer(obj, kFunctionDataOffset, v);
+ IteratePointers(obj, SharedFunctionInfo::kStartOfStrongFieldsOffset,
+ SharedFunctionInfo::kEndOfStrongFieldsOffset, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class AllocationSite::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ STATIC_ASSERT(AllocationSite::kCommonPointerFieldEndOffset ==
+ AllocationSite::kPretenureDataOffset);
+ STATIC_ASSERT(AllocationSite::kPretenureDataOffset + kInt32Size ==
+ AllocationSite::kPretenureCreateCountOffset);
+ STATIC_ASSERT(AllocationSite::kPretenureCreateCountOffset + kInt32Size ==
+ AllocationSite::kWeakNextOffset);
+
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ if (offset >= AllocationSite::kStartOffset &&
+ offset < AllocationSite::kCommonPointerFieldEndOffset) {
+ return true;
+ }
+ // check for weak_next offset
+ if (map.instance_size() == AllocationSite::kSizeWithWeakNext &&
+ offset == AllocationSite::kWeakNextOffset) {
+ return true;
+ }
+ return false;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ // Iterate over all the common pointer fields
+ IteratePointers(obj, AllocationSite::kStartOffset,
+ AllocationSite::kCommonPointerFieldEndOffset, v);
+ // Skip PretenureDataOffset and PretenureCreateCount which are Int32 fields.
+ // Visit weak_next only if it has weak_next field.
+ if (object_size == AllocationSite::kSizeWithWeakNext) {
+ IterateCustomWeakPointers(obj, AllocationSite::kWeakNextOffset,
+ AllocationSite::kSizeWithWeakNext, v);
+ }
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class JSArrayBuffer::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ if (offset < kEndOfTaggedFieldsOffset) return true;
+ if (offset < kHeaderSize) return false;
+ return IsValidJSObjectSlotImpl(map, obj, offset);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ // JSArrayBuffer instances contain raw data that the GC does not know about.
+ IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v);
+ IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class JSTypedArray::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ if (offset < kEndOfTaggedFieldsOffset) return true;
+ // TODO(v8:4153): Remove this.
+ if (offset == kBasePointerOffset) return true;
+ if (offset < kHeaderSize) return false;
+ return IsValidJSObjectSlotImpl(map, obj, offset);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ // JSTypedArray contains raw data that the GC does not know about.
+ IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v);
+ // TODO(v8:4153): Remove this.
+ IteratePointer(obj, kBasePointerOffset, v);
+ IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class JSDataView::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ if (offset < kEndOfTaggedFieldsOffset) return true;
+ if (offset < kHeaderSize) return false;
+ return IsValidJSObjectSlotImpl(map, obj, offset);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ // JSDataView contains raw data that the GC does not know about.
+ IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v);
+ IterateJSObjectBodyImpl(map, obj, kHeaderSize, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+template <typename Derived>
+class V8_EXPORT_PRIVATE SmallOrderedHashTable<Derived>::BodyDescriptor final
+ : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ Derived table = Derived::cast(obj);
+ // Only data table part contains tagged values.
+ return (offset >= DataTableStartOffset()) &&
+ (offset < table.GetBucketsStartOffset());
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ Derived table = Derived::cast(obj);
+ int start_offset = DataTableStartOffset();
+ int end_offset = table.GetBucketsStartOffset();
+ IteratePointers(obj, start_offset, end_offset, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ Derived table = Derived::cast(obj);
+ return table.SizeFor(table.Capacity());
+ }
+};
+
+class ByteArray::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {}
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ return ByteArray::SizeFor(ByteArray::cast(obj).synchronized_length());
+ }
+};
+
+class BytecodeArray::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return offset >= kConstantPoolOffset &&
+ offset <= kSourcePositionTableOffset;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointer(obj, kConstantPoolOffset, v);
+ IteratePointer(obj, kHandlerTableOffset, v);
+ IteratePointer(obj, kSourcePositionTableOffset, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ return BytecodeArray::SizeFor(
+ BytecodeArray::cast(obj).synchronized_length());
+ }
+};
+
+class BigInt::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {}
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ return BigInt::SizeFor(BigInt::cast(obj).synchronized_length());
+ }
+};
+
+class FixedDoubleArray::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {}
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ return FixedDoubleArray::SizeFor(
+ FixedDoubleArray::cast(obj).synchronized_length());
+ }
+};
+
+class FeedbackMetadata::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {}
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ return FeedbackMetadata::SizeFor(
+ FeedbackMetadata::cast(obj).synchronized_slot_count());
+ }
+};
+
+class FeedbackVector::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return offset == kSharedFunctionInfoOffset ||
+ offset == kOptimizedCodeWeakOrSmiOffset ||
+ offset == kClosureFeedbackCellArrayOffset ||
+ offset >= kFeedbackSlotsOffset;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointer(obj, kSharedFunctionInfoOffset, v);
+ IterateMaybeWeakPointer(obj, kOptimizedCodeWeakOrSmiOffset, v);
+ IteratePointer(obj, kClosureFeedbackCellArrayOffset, v);
+ IterateMaybeWeakPointers(obj, kFeedbackSlotsOffset, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ return FeedbackVector::SizeFor(FeedbackVector::cast(obj).length());
+ }
+};
+
+class PreparseData::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return offset >= PreparseData::cast(obj).inner_start_offset();
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ PreparseData data = PreparseData::cast(obj);
+ int start_offset = data.inner_start_offset();
+ int end_offset = start_offset + data.children_length() * kTaggedSize;
+ IteratePointers(obj, start_offset, end_offset, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ PreparseData data = PreparseData::cast(obj);
+ return PreparseData::SizeFor(data.data_length(), data.children_length());
+ }
+};
+
+class PrototypeInfo::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return offset >= HeapObject::kHeaderSize;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointers(obj, HeapObject::kHeaderSize, kObjectCreateMapOffset, v);
+ IterateMaybeWeakPointer(obj, kObjectCreateMapOffset, v);
+ IteratePointers(obj, kObjectCreateMapOffset + kTaggedSize, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ return obj.SizeFromMap(map);
+ }
+};
+
+class JSWeakCollection::BodyDescriptorImpl final : public BodyDescriptorBase {
+ public:
+ STATIC_ASSERT(kTableOffset + kTaggedSize == kSizeOfAllWeakCollections);
+
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return IsValidJSObjectSlotImpl(map, obj, offset);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IterateJSObjectBodyImpl(map, obj, kPropertiesOrHashOffset, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class Foreign::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ v->VisitExternalReference(
+ Foreign::cast(obj), reinterpret_cast<Address*>(
+ obj.RawField(kForeignAddressOffset).address()));
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) { return kSize; }
+};
+
+class ExternalOneByteString::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {}
+
+ static inline int SizeOf(Map map, HeapObject object) { return kSize; }
+};
+
+class ExternalTwoByteString::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {}
+
+ static inline int SizeOf(Map map, HeapObject object) { return kSize; }
+};
+
+class Code::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ STATIC_ASSERT(kRelocationInfoOffset + kTaggedSize ==
+ kDeoptimizationDataOffset);
+ STATIC_ASSERT(kDeoptimizationDataOffset + kTaggedSize ==
+ kSourcePositionTableOffset);
+ STATIC_ASSERT(kSourcePositionTableOffset + kTaggedSize ==
+ kCodeDataContainerOffset);
+ STATIC_ASSERT(kCodeDataContainerOffset + kTaggedSize == kDataStart);
+
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ // Slots in code can't be invalid because we never trim code objects.
+ return true;
+ }
+
+ static constexpr int kRelocModeMask =
+ RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
+ RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET) |
+ RelocInfo::ModeMask(RelocInfo::FULL_EMBEDDED_OBJECT) |
+ RelocInfo::ModeMask(RelocInfo::COMPRESSED_EMBEDDED_OBJECT) |
+ RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
+ RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) |
+ RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) |
+ RelocInfo::ModeMask(RelocInfo::OFF_HEAP_TARGET) |
+ RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, ObjectVisitor* v) {
+ // GC does not visit data/code in the header and in the body directly.
+ IteratePointers(obj, kRelocationInfoOffset, kDataStart, v);
+
+ RelocIterator it(Code::cast(obj), kRelocModeMask);
+ v->VisitRelocInfo(&it);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IterateBody(map, obj, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return Code::unchecked_cast(object).CodeSize();
+ }
+};
+
+class SeqOneByteString::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {}
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ SeqOneByteString string = SeqOneByteString::cast(obj);
+ return string.SizeFor(string.synchronized_length());
+ }
+};
+
+class SeqTwoByteString::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) { return false; }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {}
+
+ static inline int SizeOf(Map map, HeapObject obj) {
+ SeqTwoByteString string = SeqTwoByteString::cast(obj);
+ return string.SizeFor(string.synchronized_length());
+ }
+};
+
+class WasmInstanceObject::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ SLOW_DCHECK(std::is_sorted(std::begin(kTaggedFieldOffsets),
+ std::end(kTaggedFieldOffsets)));
+ STATIC_ASSERT(sizeof(*kTaggedFieldOffsets) == sizeof(uint16_t));
+ if (offset < int{8 * sizeof(*kTaggedFieldOffsets)} &&
+ std::binary_search(std::begin(kTaggedFieldOffsets),
+ std::end(kTaggedFieldOffsets),
+ static_cast<uint16_t>(offset))) {
+ return true;
+ }
+ return IsValidJSObjectSlotImpl(map, obj, offset);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointers(obj, kPropertiesOrHashOffset, JSObject::kHeaderSize, v);
+ for (uint16_t offset : kTaggedFieldOffsets) {
+ IteratePointer(obj, offset, v);
+ }
+ IterateJSObjectBodyImpl(map, obj, kSize, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return map.instance_size();
+ }
+};
+
+class Map::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ static_assert(
+ Map::kEndOfStrongFieldsOffset == Map::kStartOfWeakFieldsOffset,
+ "Leverage that weak fields directly follow strong fields for the "
+ "check below");
+ return offset >= Map::kStartOfStrongFieldsOffset &&
+ offset < Map::kEndOfWeakFieldsOffset;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointers(obj, Map::kStartOfStrongFieldsOffset,
+ Map::kEndOfStrongFieldsOffset, v);
+ IterateMaybeWeakPointer(obj, kTransitionsOrPrototypeInfoOffset, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject obj) { return Map::kSize; }
+};
+
+class DataHandler::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return offset >= HeapObject::kHeaderSize;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ static_assert(kSmiHandlerOffset < kData1Offset,
+ "Field order must be in sync with this iteration code");
+ static_assert(kData1Offset < kSizeWithData1,
+ "Field order must be in sync with this iteration code");
+ IteratePointers(obj, kSmiHandlerOffset, kData1Offset, v);
+ IterateMaybeWeakPointers(obj, kData1Offset, object_size, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return object.SizeFromMap(map);
+ }
+};
+
+class NativeContext::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return offset < NativeContext::kEndOfTaggedFieldsOffset;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointers(obj, NativeContext::kStartOfStrongFieldsOffset,
+ NativeContext::kEndOfStrongFieldsOffset, v);
+ IterateCustomWeakPointers(obj, NativeContext::kStartOfWeakFieldsOffset,
+ NativeContext::kEndOfWeakFieldsOffset, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return NativeContext::kSize;
+ }
+};
+
+class CodeDataContainer::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return offset >= CodeDataContainer::kHeaderSize &&
+ offset < CodeDataContainer::kSize;
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ IteratePointers(obj, CodeDataContainer::kHeaderSize,
+ CodeDataContainer::kPointerFieldsStrongEndOffset, v);
+ IterateCustomWeakPointers(
+ obj, CodeDataContainer::kPointerFieldsStrongEndOffset,
+ CodeDataContainer::kPointerFieldsWeakEndOffset, v);
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return CodeDataContainer::kSize;
+ }
+};
+
+class EmbedderDataArray::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+#ifdef V8_COMPRESS_POINTERS
+ STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
+ STATIC_ASSERT(base::bits::IsPowerOfTwo(kEmbedderDataSlotSize));
+ return (offset < EmbedderDataArray::kHeaderSize) ||
+ (((offset - EmbedderDataArray::kHeaderSize) &
+ (kEmbedderDataSlotSize - 1)) ==
+ EmbedderDataSlot::kTaggedPayloadOffset);
+#else
+ STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
+ // We store raw aligned pointers as Smis, so it's safe to iterate the whole
+ // array.
+ return true;
+#endif
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+#ifdef V8_COMPRESS_POINTERS
+ STATIC_ASSERT(kEmbedderDataSlotSize == 2 * kTaggedSize);
+ // Iterate only tagged payload of the embedder slots and skip raw payload.
+ for (int offset = EmbedderDataArray::OffsetOfElementAt(0) +
+ EmbedderDataSlot::kTaggedPayloadOffset;
+ offset < object_size; offset += kEmbedderDataSlotSize) {
+ IteratePointer(obj, offset, v);
+ }
+#else
+ // We store raw aligned pointers as Smis, so it's safe to iterate the whole
+ // array.
+ STATIC_ASSERT(kEmbedderDataSlotSize == kTaggedSize);
+ IteratePointers(obj, EmbedderDataArray::kHeaderSize, object_size, v);
+#endif
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return object.SizeFromMap(map);
+ }
+};
+
+template <typename Op, typename ReturnType, typename T1, typename T2,
+ typename T3, typename T4>
+ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
+ if (type < FIRST_NONSTRING_TYPE) {
+ switch (type & kStringRepresentationMask) {
+ case kSeqStringTag:
+ return ReturnType();
+ case kConsStringTag:
+ return Op::template apply<ConsString::BodyDescriptor>(p1, p2, p3, p4);
+ case kThinStringTag:
+ return Op::template apply<ThinString::BodyDescriptor>(p1, p2, p3, p4);
+ case kSlicedStringTag:
+ return Op::template apply<SlicedString::BodyDescriptor>(p1, p2, p3, p4);
+ case kExternalStringTag:
+ if ((type & kStringEncodingMask) == kOneByteStringTag) {
+ return Op::template apply<ExternalOneByteString::BodyDescriptor>(
+ p1, p2, p3, p4);
+ } else {
+ return Op::template apply<ExternalTwoByteString::BodyDescriptor>(
+ p1, p2, p3, p4);
+ }
+ }
+ UNREACHABLE();
+ }
+
+ switch (type) {
+ case EMBEDDER_DATA_ARRAY_TYPE:
+ return Op::template apply<EmbedderDataArray::BodyDescriptor>(p1, p2, p3,
+ p4);
+ case FIXED_ARRAY_TYPE:
+ case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
+ case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE:
+ case HASH_TABLE_TYPE:
+ case ORDERED_HASH_MAP_TYPE:
+ case ORDERED_HASH_SET_TYPE:
+ case ORDERED_NAME_DICTIONARY_TYPE:
+ case NAME_DICTIONARY_TYPE:
+ case GLOBAL_DICTIONARY_TYPE:
+ case NUMBER_DICTIONARY_TYPE:
+ case SIMPLE_NUMBER_DICTIONARY_TYPE:
+ case STRING_TABLE_TYPE:
+ case SCOPE_INFO_TYPE:
+ case SCRIPT_CONTEXT_TABLE_TYPE:
+ return Op::template apply<FixedArray::BodyDescriptor>(p1, p2, p3, p4);
+ case EPHEMERON_HASH_TABLE_TYPE:
+ return Op::template apply<EphemeronHashTable::BodyDescriptor>(p1, p2, p3,
+ p4);
+ case AWAIT_CONTEXT_TYPE:
+ case BLOCK_CONTEXT_TYPE:
+ case CATCH_CONTEXT_TYPE:
+ case DEBUG_EVALUATE_CONTEXT_TYPE:
+ case EVAL_CONTEXT_TYPE:
+ case FUNCTION_CONTEXT_TYPE:
+ case MODULE_CONTEXT_TYPE:
+ case SCRIPT_CONTEXT_TYPE:
+ case WITH_CONTEXT_TYPE:
+ return Op::template apply<Context::BodyDescriptor>(p1, p2, p3, p4);
+ case NATIVE_CONTEXT_TYPE:
+ return Op::template apply<NativeContext::BodyDescriptor>(p1, p2, p3, p4);
+ case WEAK_FIXED_ARRAY_TYPE:
+ return Op::template apply<WeakFixedArray::BodyDescriptor>(p1, p2, p3, p4);
+ case WEAK_ARRAY_LIST_TYPE:
+ return Op::template apply<WeakArrayList::BodyDescriptor>(p1, p2, p3, p4);
+ case FIXED_DOUBLE_ARRAY_TYPE:
+ return ReturnType();
+ case FEEDBACK_METADATA_TYPE:
+ return Op::template apply<FeedbackMetadata::BodyDescriptor>(p1, p2, p3,
+ p4);
+ case PROPERTY_ARRAY_TYPE:
+ return Op::template apply<PropertyArray::BodyDescriptor>(p1, p2, p3, p4);
+ case DESCRIPTOR_ARRAY_TYPE:
+ return Op::template apply<DescriptorArray::BodyDescriptor>(p1, p2, p3,
+ p4);
+ case TRANSITION_ARRAY_TYPE:
+ return Op::template apply<TransitionArray::BodyDescriptor>(p1, p2, p3,
+ p4);
+ case FEEDBACK_CELL_TYPE:
+ return Op::template apply<FeedbackCell::BodyDescriptor>(p1, p2, p3, p4);
+ case FEEDBACK_VECTOR_TYPE:
+ return Op::template apply<FeedbackVector::BodyDescriptor>(p1, p2, p3, p4);
+ case JS_OBJECT_TYPE:
+ case JS_ERROR_TYPE:
+ case JS_ARGUMENTS_TYPE:
+ case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
+ case JS_PROMISE_TYPE:
+ case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
+ case JS_GENERATOR_OBJECT_TYPE:
+ case JS_ASYNC_FUNCTION_OBJECT_TYPE:
+ case JS_ASYNC_GENERATOR_OBJECT_TYPE:
+ case JS_VALUE_TYPE:
+ case JS_DATE_TYPE:
+ case JS_ARRAY_TYPE:
+ case JS_ARRAY_ITERATOR_TYPE:
+ case JS_MODULE_NAMESPACE_TYPE:
+ case JS_SET_TYPE:
+ case JS_MAP_TYPE:
+ case JS_SET_KEY_VALUE_ITERATOR_TYPE:
+ case JS_SET_VALUE_ITERATOR_TYPE:
+ case JS_MAP_KEY_ITERATOR_TYPE:
+ case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
+ case JS_MAP_VALUE_ITERATOR_TYPE:
+ case JS_STRING_ITERATOR_TYPE:
+ case JS_REGEXP_STRING_ITERATOR_TYPE:
+ case JS_REGEXP_TYPE:
+ case JS_GLOBAL_PROXY_TYPE:
+ case JS_GLOBAL_OBJECT_TYPE:
+ case JS_API_OBJECT_TYPE:
+ case JS_SPECIAL_API_OBJECT_TYPE:
+ case JS_MESSAGE_OBJECT_TYPE:
+ case JS_BOUND_FUNCTION_TYPE:
+ case JS_FINALIZATION_GROUP_CLEANUP_ITERATOR_TYPE:
+ case JS_FINALIZATION_GROUP_TYPE:
+#ifdef V8_INTL_SUPPORT
+ case JS_INTL_V8_BREAK_ITERATOR_TYPE:
+ case JS_INTL_COLLATOR_TYPE:
+ case JS_INTL_DATE_TIME_FORMAT_TYPE:
+ case JS_INTL_LIST_FORMAT_TYPE:
+ case JS_INTL_LOCALE_TYPE:
+ case JS_INTL_NUMBER_FORMAT_TYPE:
+ case JS_INTL_PLURAL_RULES_TYPE:
+ case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
+ case JS_INTL_SEGMENT_ITERATOR_TYPE:
+ case JS_INTL_SEGMENTER_TYPE:
+#endif // V8_INTL_SUPPORT
+ case WASM_EXCEPTION_TYPE:
+ case WASM_GLOBAL_TYPE:
+ case WASM_MEMORY_TYPE:
+ case WASM_MODULE_TYPE:
+ case WASM_TABLE_TYPE:
+ return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3, p4);
+ case WASM_INSTANCE_TYPE:
+ return Op::template apply<WasmInstanceObject::BodyDescriptor>(p1, p2, p3,
+ p4);
+ case JS_WEAK_MAP_TYPE:
+ case JS_WEAK_SET_TYPE:
+ return Op::template apply<JSWeakCollection::BodyDescriptor>(p1, p2, p3,
+ p4);
+ case JS_ARRAY_BUFFER_TYPE:
+ return Op::template apply<JSArrayBuffer::BodyDescriptor>(p1, p2, p3, p4);
+ case JS_DATA_VIEW_TYPE:
+ return Op::template apply<JSDataView::BodyDescriptor>(p1, p2, p3, p4);
+ case JS_TYPED_ARRAY_TYPE:
+ return Op::template apply<JSTypedArray::BodyDescriptor>(p1, p2, p3, p4);
+ case JS_FUNCTION_TYPE:
+ return Op::template apply<JSFunction::BodyDescriptor>(p1, p2, p3, p4);
+ case WEAK_CELL_TYPE:
+ return Op::template apply<WeakCell::BodyDescriptor>(p1, p2, p3, p4);
+ case JS_WEAK_REF_TYPE:
+ return Op::template apply<JSWeakRef::BodyDescriptor>(p1, p2, p3, p4);
+ case ODDBALL_TYPE:
+ return Op::template apply<Oddball::BodyDescriptor>(p1, p2, p3, p4);
+ case JS_PROXY_TYPE:
+ return Op::template apply<JSProxy::BodyDescriptor>(p1, p2, p3, p4);
+ case FOREIGN_TYPE:
+ return Op::template apply<Foreign::BodyDescriptor>(p1, p2, p3, p4);
+ case MAP_TYPE:
+ return Op::template apply<Map::BodyDescriptor>(p1, p2, p3, p4);
+ case CODE_TYPE:
+ return Op::template apply<Code::BodyDescriptor>(p1, p2, p3, p4);
+ case CELL_TYPE:
+ return Op::template apply<Cell::BodyDescriptor>(p1, p2, p3, p4);
+ case PROPERTY_CELL_TYPE:
+ return Op::template apply<PropertyCell::BodyDescriptor>(p1, p2, p3, p4);
+ case SYMBOL_TYPE:
+ return Op::template apply<Symbol::BodyDescriptor>(p1, p2, p3, p4);
+ case BYTECODE_ARRAY_TYPE:
+ return Op::template apply<BytecodeArray::BodyDescriptor>(p1, p2, p3, p4);
+ case SMALL_ORDERED_HASH_SET_TYPE:
+ return Op::template apply<
+ SmallOrderedHashTable<SmallOrderedHashSet>::BodyDescriptor>(p1, p2,
+ p3, p4);
+ case SMALL_ORDERED_HASH_MAP_TYPE:
+ return Op::template apply<
+ SmallOrderedHashTable<SmallOrderedHashMap>::BodyDescriptor>(p1, p2,
+ p3, p4);
+ case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
+ return Op::template apply<
+ SmallOrderedHashTable<SmallOrderedNameDictionary>::BodyDescriptor>(
+ p1, p2, p3, p4);
+ case CODE_DATA_CONTAINER_TYPE:
+ return Op::template apply<CodeDataContainer::BodyDescriptor>(p1, p2, p3,
+ p4);
+ case PREPARSE_DATA_TYPE:
+ return Op::template apply<PreparseData::BodyDescriptor>(p1, p2, p3, p4);
+ case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE:
+ return Op::template apply<
+ UncompiledDataWithoutPreparseData::BodyDescriptor>(p1, p2, p3, p4);
+ case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE:
+ return Op::template apply<UncompiledDataWithPreparseData::BodyDescriptor>(
+ p1, p2, p3, p4);
+ case HEAP_NUMBER_TYPE:
+ case MUTABLE_HEAP_NUMBER_TYPE:
+ case FILLER_TYPE:
+ case BYTE_ARRAY_TYPE:
+ case FREE_SPACE_TYPE:
+ case BIGINT_TYPE:
+ return ReturnType();
+
+ case SHARED_FUNCTION_INFO_TYPE: {
+ return Op::template apply<SharedFunctionInfo::BodyDescriptor>(p1, p2, p3,
+ p4);
+ }
+ case ALLOCATION_SITE_TYPE:
+ return Op::template apply<AllocationSite::BodyDescriptor>(p1, p2, p3, p4);
+
+#define MAKE_STRUCT_CASE(TYPE, Name, name) case TYPE:
+ STRUCT_LIST(MAKE_STRUCT_CASE)
+#undef MAKE_STRUCT_CASE
+ if (type == PROTOTYPE_INFO_TYPE) {
+ return Op::template apply<PrototypeInfo::BodyDescriptor>(p1, p2, p3,
+ p4);
+ } else if (type == WASM_CAPI_FUNCTION_DATA_TYPE) {
+ return Op::template apply<WasmCapiFunctionData::BodyDescriptor>(p1, p2,
+ p3, p4);
+ } else {
+ return Op::template apply<StructBodyDescriptor>(p1, p2, p3, p4);
+ }
+ case CALL_HANDLER_INFO_TYPE:
+ return Op::template apply<StructBodyDescriptor>(p1, p2, p3, p4);
+ case LOAD_HANDLER_TYPE:
+ case STORE_HANDLER_TYPE:
+ return Op::template apply<DataHandler::BodyDescriptor>(p1, p2, p3, p4);
+ default:
+ PrintF("Unknown type: %d\n", type);
+ UNREACHABLE();
+ }
+}
+
+template <typename ObjectVisitor>
+void HeapObject::IterateFast(ObjectVisitor* v) {
+ BodyDescriptorBase::IteratePointer(*this, kMapOffset, v);
+ IterateBodyFast(v);
+}
+
+template <typename ObjectVisitor>
+void HeapObject::IterateBodyFast(ObjectVisitor* v) {
+ Map m = map();
+ IterateBodyFast(m, SizeFromMap(m), v);
+}
+
+struct CallIterateBody {
+ template <typename BodyDescriptor, typename ObjectVisitor>
+ static void apply(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ BodyDescriptor::IterateBody(map, obj, object_size, v);
+ }
+};
+
+template <typename ObjectVisitor>
+void HeapObject::IterateBodyFast(Map map, int object_size, ObjectVisitor* v) {
+ BodyDescriptorApply<CallIterateBody, void>(map.instance_type(), map, *this,
+ object_size, v);
+}
+
+class EphemeronHashTable::BodyDescriptor final : public BodyDescriptorBase {
+ public:
+ static bool IsValidSlot(Map map, HeapObject obj, int offset) {
+ return (offset >= EphemeronHashTable::kHeaderSize);
+ }
+
+ template <typename ObjectVisitor>
+ static inline void IterateBody(Map map, HeapObject obj, int object_size,
+ ObjectVisitor* v) {
+ int entries_start = EphemeronHashTable::kHeaderSize +
+ EphemeronHashTable::kElementsStartIndex * kTaggedSize;
+ IteratePointers(obj, EphemeronHashTable::kHeaderSize, entries_start, v);
+ EphemeronHashTable table = EphemeronHashTable::unchecked_cast(obj);
+ int entries = table.Capacity();
+ for (int i = 0; i < entries; ++i) {
+ const int key_index = EphemeronHashTable::EntryToIndex(i);
+ const int value_index = EphemeronHashTable::EntryToValueIndex(i);
+ IterateEphemeron(obj, i, OffsetOfElementAt(key_index),
+ OffsetOfElementAt(value_index), v);
+ }
+ }
+
+ static inline int SizeOf(Map map, HeapObject object) {
+ return object.SizeFromMap(map);
+ }
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_OBJECTS_OBJECTS_BODY_DESCRIPTORS_INL_H_