// 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 <algorithm> #include "src/codegen/reloc-info.h" #include "src/ic/handler-configuration.h" #include "src/objects/arguments-inl.h" #include "src/objects/bigint.h" #include "src/objects/call-site-info.h" #include "src/objects/cell.h" #include "src/objects/data-handler.h" #include "src/objects/embedder-data-array-inl.h" #include "src/objects/fixed-array.h" #include "src/objects/foreign-inl.h" #include "src/objects/free-space-inl.h" #include "src/objects/hash-table.h" #include "src/objects/heap-number.h" #include "src/objects/js-collection.h" #include "src/objects/js-weak-refs.h" #include "src/objects/literal-objects.h" #include "src/objects/megadom-handler-inl.h" #include "src/objects/objects-body-descriptors.h" #include "src/objects/ordered-hash-table-inl.h" #include "src/objects/property-descriptor-object.h" #include "src/objects/source-text-module.h" #include "src/objects/swiss-name-dictionary-inl.h" #include "src/objects/synthetic-module.h" #include "src/objects/template-objects.h" #include "src/objects/torque-defined-classes-inl.h" #include "src/objects/transitions.h" #include "src/objects/turbofan-types-inl.h" #if V8_ENABLE_WEBASSEMBLY #include "src/wasm/wasm-objects-inl.h" #endif // V8_ENABLE_WEBASSEMBLY 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 return true; } 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_end_offset = JSObject::GetHeaderSize(map); int inobject_fields_start_offset = map.GetInObjectPropertyOffset(0); // We are always requested to process header and embedder fields. DCHECK_LE(inobject_fields_start_offset, end_offset); // Embedder fields are located between header and inobject properties. if (header_end_offset < inobject_fields_start_offset) { // There are embedder fields. DCHECK_EQ(header_end_offset, JSObject::GetEmbedderFieldsStartOffset(map)); IteratePointers(obj, start_offset, header_end_offset, v); for (int offset = header_end_offset; offset < inobject_fields_start_offset; offset += kEmbedderDataSlotSize) { IteratePointer(obj, offset + EmbedderDataSlot::kTaggedPayloadOffset, v); v->VisitExternalPointer( obj, obj.RawExternalPointerField( offset + EmbedderDataSlot::kExternalPointerOffset)); } // Proceed processing inobject properties. start_offset = inobject_fields_start_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 IteratePointers(obj, start_offset, end_offset, v); } template <typename ObjectVisitor> DISABLE_CFI_PERF void BodyDescriptorBase::IteratePointers(HeapObject obj, int start_offset, int end_offset, ObjectVisitor* v) { if (start_offset == HeapObject::kMapOffset) { v->VisitMapPointer(obj); start_offset += kTaggedSize; } v->VisitPointers(obj, obj.RawField(start_offset), obj.RawField(end_offset)); } template <typename ObjectVisitor> void BodyDescriptorBase::IteratePointer(HeapObject obj, int offset, ObjectVisitor* v) { DCHECK_NE(offset, HeapObject::kMapOffset); 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) { DCHECK_NE(offset, HeapObject::kMapOffset); 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 HeapNumber::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 HeapNumber::kSize; } }; // This is a descriptor for one/two pointer fillers. class FreeSpaceFillerBodyDescriptor final : public DataOnlyBodyDescriptor { public: static inline int SizeOf(Map map, HeapObject raw_object) { return map.instance_size(); } }; class FreeSpace::BodyDescriptor final : public DataOnlyBodyDescriptor { public: static inline int SizeOf(Map map, HeapObject raw_object) { return FreeSpace::unchecked_cast(raw_object).Size(); } }; 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); IterateCustomWeakPointer(obj, kUnregisterTokenOffset, v); IteratePointers(obj, kUnregisterTokenOffset + 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 JSFinalizationRegistry::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, JSObject::BodyDescriptor::kStartOffset, kNextDirtyOffset, v); IterateCustomWeakPointer(obj, kNextDirtyOffset, v); IterateJSObjectBodyImpl(map, obj, kNextDirtyOffset + kTaggedSize, object_size, 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 JSFunction::BodyDescriptor final : public BodyDescriptorBase { public: static const int kStartOffset = JSObject::BodyDescriptor::kStartOffset; 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) { // Iterate JSFunction header fields first. int header_size = JSFunction::GetHeaderSize(map.has_prototype_slot()); DCHECK_GE(object_size, header_size); IteratePointers(obj, kStartOffset, kCodeOffset, v); // Code field is treated as a custom weak pointer. This field is visited as // a weak pointer if the Code is baseline code and the bytecode array // corresponding to this function is old. In the rest of the cases this // field is treated as strong pointer. IterateCustomWeakPointer(obj, kCodeOffset, v); // Iterate rest of the header fields DCHECK_GE(header_size, kCodeOffset); IteratePointers(obj, kCodeOffset + kTaggedSize, header_size, v); // Iterate rest of the fields starting after the header. IterateJSObjectBodyImpl(map, obj, header_size, object_size, 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(); } }; class JSExternalObject::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) { IteratePointers(obj, kPropertiesOrHashOffset, kEndOfTaggedFieldsOffset, v); v->VisitExternalPointer(obj, obj.RawExternalPointerField(kValueOffset)); } 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 Derived::SizeFor(table.Capacity()); } }; class V8_EXPORT_PRIVATE SwissNameDictionary::BodyDescriptor final : public BodyDescriptorBase { public: static bool IsValidSlot(Map map, HeapObject obj, int offset) { // Using |unchecked_cast| here and elsewhere in this class because the // Scavenger may be calling us while the map word contains the forwarding // address (a Smi) rather than a map. SwissNameDictionary table = SwissNameDictionary::unchecked_cast(obj); STATIC_ASSERT(MetaTablePointerOffset() + kTaggedSize == DataTableStartOffset()); return offset >= MetaTablePointerOffset() && (offset < table.DataTableEndOffset(table.Capacity())); } template <typename ObjectVisitor> static inline void IterateBody(Map map, HeapObject obj, int object_size, ObjectVisitor* v) { SwissNameDictionary table = SwissNameDictionary::unchecked_cast(obj); STATIC_ASSERT(MetaTablePointerOffset() + kTaggedSize == DataTableStartOffset()); int start_offset = MetaTablePointerOffset(); int end_offset = table.DataTableEndOffset(table.Capacity()); IteratePointers(obj, start_offset, end_offset, v); } static inline int SizeOf(Map map, HeapObject obj) { SwissNameDictionary table = SwissNameDictionary::unchecked_cast(obj); return SwissNameDictionary::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).length(kAcquireLoad)); } }; 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).length(kAcquireLoad)); } }; 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).length(kAcquireLoad)); } }; 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).length(kAcquireLoad)); } }; 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).slot_count(kAcquireLoad)); } }; 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 PromiseOnStack::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, Struct::kHeaderSize, kPromiseOffset, v); IterateMaybeWeakPointer(obj, kPromiseOffset, v); STATIC_ASSERT(kPromiseOffset + kTaggedSize == kHeaderSize); } static inline int SizeOf(Map map, HeapObject obj) { return obj.SizeFromMap(map); } }; 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); STATIC_ASSERT(kObjectCreateMapOffset + kTaggedSize == kHeaderSize); } static inline int SizeOf(Map map, HeapObject obj) { return obj.SizeFromMap(map); } }; class JSWeakCollection::BodyDescriptorImpl final : public BodyDescriptorBase { public: STATIC_ASSERT(kTableOffset + kTaggedSize == kHeaderSizeOfAllWeakCollections); 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())); v->VisitExternalPointer(obj, obj.RawExternalPointerField(kForeignAddressOffset)); } static inline int SizeOf(Map map, HeapObject object) { return kSize; } }; #if V8_ENABLE_WEBASSEMBLY class WasmTypeInfo::BodyDescriptor final : public BodyDescriptorBase { public: static bool IsValidSlot(Map map, HeapObject obj, int offset) { UNREACHABLE(); } template <typename ObjectVisitor> static inline void IterateBody(Map map, HeapObject obj, int object_size, ObjectVisitor* v) { Foreign::BodyDescriptor::IterateBody<ObjectVisitor>(map, obj, object_size, v); IteratePointer(obj, kSupertypesOffset, v); IteratePointer(obj, kSubtypesOffset, v); IteratePointer(obj, kInstanceOffset, v); } static inline int SizeOf(Map map, HeapObject object) { return kSize; } }; class WasmApiFunctionRef::BodyDescriptor final : public BodyDescriptorBase { public: static bool IsValidSlot(Map map, HeapObject obj, int offset) { UNREACHABLE(); } template <typename ObjectVisitor> static inline void IterateBody(Map map, HeapObject obj, int object_size, ObjectVisitor* v) { IteratePointers(obj, kStartOfStrongFieldsOffset, kEndOfStrongFieldsOffset, v); } static inline int SizeOf(Map map, HeapObject object) { return kSize; } }; class WasmInternalFunction::BodyDescriptor final : public BodyDescriptorBase { public: static bool IsValidSlot(Map map, HeapObject obj, int offset) { UNREACHABLE(); } template <typename ObjectVisitor> static inline void IterateBody(Map map, HeapObject obj, int object_size, ObjectVisitor* v) { Foreign::BodyDescriptor::IterateBody<ObjectVisitor>(map, obj, object_size, v); IteratePointers(obj, kStartOfStrongFieldsOffset, kEndOfStrongFieldsOffset, v); } static inline int SizeOf(Map map, HeapObject object) { return kSize; } }; 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, kHeaderSize, object_size, v); } static inline int SizeOf(Map map, HeapObject object) { return map.instance_size(); } }; class WasmArray::BodyDescriptor final : public BodyDescriptorBase { public: static bool IsValidSlot(Map map, HeapObject obj, int offset) { // Fields in WasmArrays never change their types in place, so // there should never be a need to call this function. UNREACHABLE(); return false; } template <typename ObjectVisitor> static inline void IterateBody(Map map, HeapObject obj, int object_size, ObjectVisitor* v) { // The type is safe to use because it's kept alive by the {map}'s // WasmTypeInfo. if (!WasmArray::GcSafeType(map)->element_type().is_reference()) return; IteratePointers(obj, WasmArray::kHeaderSize, object_size, v); } static inline int SizeOf(Map map, HeapObject object) { return WasmArray::SizeFor(map, WasmArray::cast(object).length()); } }; class WasmStruct::BodyDescriptor final : public BodyDescriptorBase { public: static bool IsValidSlot(Map map, HeapObject obj, int offset) { // Fields in WasmStructs never change their types in place, so // there should never be a need to call this function. UNREACHABLE(); return false; } template <typename ObjectVisitor> static inline void IterateBody(Map map, HeapObject obj, int object_size, ObjectVisitor* v) { WasmStruct wasm_struct = WasmStruct::cast(obj); // The {type} is safe to use because it's kept alive by the {map}'s // WasmTypeInfo. wasm::StructType* type = WasmStruct::GcSafeType(map); for (uint32_t i = 0; i < type->field_count(); i++) { if (!type->field(i).is_reference()) continue; int offset = static_cast<int>(type->field_offset(i)); v->VisitPointer(wasm_struct, wasm_struct.RawField(offset)); } } static inline int SizeOf(Map map, HeapObject object) { return WasmStruct::GcSafeSize(map); } }; #endif // V8_ENABLE_WEBASSEMBLY 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) { ExternalString string = ExternalString::cast(obj); v->VisitExternalPointer(obj, string.RawExternalPointerField(kResourceOffset)); if (string.is_uncached()) return; v->VisitExternalPointer( obj, string.RawExternalPointerField(kResourceDataOffset)); } 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) { ExternalString string = ExternalString::cast(obj); v->VisitExternalPointer(obj, string.RawExternalPointerField(kResourceOffset)); if (string.is_uncached()) return; v->VisitExternalPointer( obj, string.RawExternalPointerField(kResourceDataOffset)); } static inline int SizeOf(Map map, HeapObject object) { return kSize; } }; class CoverageInfo::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) { CoverageInfo info = CoverageInfo::cast(object); return CoverageInfo::SizeFor(info.slot_count()); } }; class Code::BodyDescriptor final : public BodyDescriptorBase { public: STATIC_ASSERT(kRelocationInfoOffset + kTaggedSize == kDeoptimizationDataOrInterpreterDataOffset); STATIC_ASSERT(kDeoptimizationDataOrInterpreterDataOffset + kTaggedSize == kPositionTableOffset); STATIC_ASSERT(kPositionTableOffset + 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::DATA_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 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); v->VisitExternalPointer(obj, obj.RawExternalPointerField(kMicrotaskQueueOffset)); } 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::kPointerFieldsWeakEndOffset; } 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); if (V8_EXTERNAL_CODE_SPACE_BOOL) { v->VisitCodePointer(obj, obj.RawCodeField(kCodeOffset)); v->VisitExternalPointer( obj, obj.RawExternalPointerField(kCodeEntryPointOffset)); } } 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); for (int offset = EmbedderDataArray::OffsetOfElementAt(0); offset < object_size; offset += kEmbedderDataSlotSize) { IteratePointer(obj, offset + EmbedderDataSlot::kTaggedPayloadOffset, v); v->VisitExternalPointer( obj, obj.RawExternalPointerField( offset + EmbedderDataSlot::kExternalPointerOffset)); } #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... Args> auto BodyDescriptorApply(InstanceType type, Args&&... args) { #define CALL_APPLY(ClassName) \ Op::template apply<ClassName::BodyDescriptor>(std::forward<Args>(args)...) if (type < FIRST_NONSTRING_TYPE) { switch (type & kStringRepresentationMask) { case kSeqStringTag: if ((type & kStringEncodingMask) == kOneByteStringTag) { return CALL_APPLY(SeqOneByteString); } else { return CALL_APPLY(SeqTwoByteString); } case kConsStringTag: return CALL_APPLY(ConsString); case kThinStringTag: return CALL_APPLY(ThinString); case kSlicedStringTag: return CALL_APPLY(SlicedString); case kExternalStringTag: if ((type & kStringEncodingMask) == kOneByteStringTag) { return CALL_APPLY(ExternalOneByteString); } else { return CALL_APPLY(ExternalTwoByteString); } } UNREACHABLE(); } if (InstanceTypeChecker::IsJSApiObject(type)) { return CALL_APPLY(JSObject); } switch (type) { case EMBEDDER_DATA_ARRAY_TYPE: return CALL_APPLY(EmbedderDataArray); 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 NAME_TO_INDEX_HASH_TABLE_TYPE: case REGISTERED_SYMBOL_TABLE_TYPE: case SCRIPT_CONTEXT_TABLE_TYPE: return CALL_APPLY(FixedArray); case EPHEMERON_HASH_TABLE_TYPE: return CALL_APPLY(EphemeronHashTable); 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 CALL_APPLY(Context); case NATIVE_CONTEXT_TYPE: return CALL_APPLY(NativeContext); case FIXED_DOUBLE_ARRAY_TYPE: return CALL_APPLY(FixedDoubleArray); case FEEDBACK_METADATA_TYPE: return CALL_APPLY(FeedbackMetadata); case PROPERTY_ARRAY_TYPE: return CALL_APPLY(PropertyArray); case TRANSITION_ARRAY_TYPE: return CALL_APPLY(TransitionArray); case FEEDBACK_CELL_TYPE: return CALL_APPLY(FeedbackCell); case COVERAGE_INFO_TYPE: return CALL_APPLY(CoverageInfo); #if V8_ENABLE_WEBASSEMBLY case WASM_API_FUNCTION_REF_TYPE: return CALL_APPLY(WasmApiFunctionRef); case WASM_ARRAY_TYPE: return CALL_APPLY(WasmArray); case WASM_CAPI_FUNCTION_DATA_TYPE: return CALL_APPLY(WasmCapiFunctionData); case WASM_EXPORTED_FUNCTION_DATA_TYPE: return CALL_APPLY(WasmExportedFunctionData); case WASM_INTERNAL_FUNCTION_TYPE: return CALL_APPLY(WasmInternalFunction); case WASM_JS_FUNCTION_DATA_TYPE: return CALL_APPLY(WasmJSFunctionData); case WASM_ON_FULFILLED_DATA_TYPE: return CALL_APPLY(WasmOnFulfilledData); case WASM_STRUCT_TYPE: return CALL_APPLY(WasmStruct); case WASM_TYPE_INFO_TYPE: return CALL_APPLY(WasmTypeInfo); #endif // V8_ENABLE_WEBASSEMBLY case JS_API_OBJECT_TYPE: case JS_ARGUMENTS_OBJECT_TYPE: case JS_ARRAY_ITERATOR_PROTOTYPE_TYPE: case JS_ARRAY_ITERATOR_TYPE: case JS_ARRAY_TYPE: case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE: case JS_ASYNC_FUNCTION_OBJECT_TYPE: case JS_ASYNC_GENERATOR_OBJECT_TYPE: case JS_BOUND_FUNCTION_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE: case JS_DATE_TYPE: case JS_ERROR_TYPE: case JS_FINALIZATION_REGISTRY_TYPE: case JS_GENERATOR_OBJECT_TYPE: case JS_GLOBAL_OBJECT_TYPE: case JS_GLOBAL_PROXY_TYPE: case JS_ITERATOR_PROTOTYPE_TYPE: case JS_MAP_ITERATOR_PROTOTYPE_TYPE: case JS_MAP_KEY_ITERATOR_TYPE: case JS_MAP_KEY_VALUE_ITERATOR_TYPE: case JS_MAP_TYPE: case JS_MAP_VALUE_ITERATOR_TYPE: case JS_MESSAGE_OBJECT_TYPE: case JS_MODULE_NAMESPACE_TYPE: case JS_OBJECT_PROTOTYPE_TYPE: case JS_OBJECT_TYPE: case JS_PRIMITIVE_WRAPPER_TYPE: case JS_PROMISE_PROTOTYPE_TYPE: case JS_PROMISE_TYPE: case JS_REG_EXP_PROTOTYPE_TYPE: case JS_REG_EXP_STRING_ITERATOR_TYPE: case JS_REG_EXP_TYPE: case JS_SET_ITERATOR_PROTOTYPE_TYPE: case JS_SET_KEY_VALUE_ITERATOR_TYPE: case JS_SET_PROTOTYPE_TYPE: case JS_SET_TYPE: case JS_SET_VALUE_ITERATOR_TYPE: case JS_SPECIAL_API_OBJECT_TYPE: case JS_SHADOW_REALM_TYPE: case JS_SHARED_STRUCT_TYPE: case JS_STRING_ITERATOR_PROTOTYPE_TYPE: case JS_STRING_ITERATOR_TYPE: case JS_TEMPORAL_CALENDAR_TYPE: case JS_TEMPORAL_DURATION_TYPE: case JS_TEMPORAL_INSTANT_TYPE: case JS_TEMPORAL_PLAIN_DATE_TYPE: case JS_TEMPORAL_PLAIN_DATE_TIME_TYPE: case JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE: case JS_TEMPORAL_PLAIN_TIME_TYPE: case JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE: case JS_TEMPORAL_TIME_ZONE_TYPE: case JS_TEMPORAL_ZONED_DATE_TIME_TYPE: case JS_TYPED_ARRAY_PROTOTYPE_TYPE: case JS_FUNCTION_TYPE: case JS_CLASS_CONSTRUCTOR_TYPE: case JS_PROMISE_CONSTRUCTOR_TYPE: case JS_REG_EXP_CONSTRUCTOR_TYPE: case JS_WRAPPED_FUNCTION_TYPE: case JS_ARRAY_CONSTRUCTOR_TYPE: #define TYPED_ARRAY_CONSTRUCTORS_SWITCH(Type, type, TYPE, Ctype) \ case TYPE##_TYPED_ARRAY_CONSTRUCTOR_TYPE: TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTORS_SWITCH) #undef TYPED_ARRAY_CONSTRUCTORS_SWITCH #ifdef V8_INTL_SUPPORT case JS_V8_BREAK_ITERATOR_TYPE: case JS_COLLATOR_TYPE: case JS_DATE_TIME_FORMAT_TYPE: case JS_DISPLAY_NAMES_TYPE: case JS_LIST_FORMAT_TYPE: case JS_LOCALE_TYPE: case JS_NUMBER_FORMAT_TYPE: case JS_PLURAL_RULES_TYPE: case JS_RELATIVE_TIME_FORMAT_TYPE: case JS_SEGMENT_ITERATOR_TYPE: case JS_SEGMENTER_TYPE: case JS_SEGMENTS_TYPE: #endif // V8_INTL_SUPPORT #if V8_ENABLE_WEBASSEMBLY case WASM_GLOBAL_OBJECT_TYPE: case WASM_MEMORY_OBJECT_TYPE: case WASM_MODULE_OBJECT_TYPE: case WASM_SUSPENDER_OBJECT_TYPE: case WASM_TABLE_OBJECT_TYPE: case WASM_TAG_OBJECT_TYPE: case WASM_VALUE_OBJECT_TYPE: #endif // V8_ENABLE_WEBASSEMBLY return CALL_APPLY(JSObject); #if V8_ENABLE_WEBASSEMBLY case WASM_INSTANCE_OBJECT_TYPE: return CALL_APPLY(WasmInstanceObject); #endif // V8_ENABLE_WEBASSEMBLY case JS_WEAK_MAP_TYPE: case JS_WEAK_SET_TYPE: return CALL_APPLY(JSWeakCollection); case JS_ARRAY_BUFFER_TYPE: return CALL_APPLY(JSArrayBuffer); case JS_DATA_VIEW_TYPE: return CALL_APPLY(JSDataView); case JS_TYPED_ARRAY_TYPE: return CALL_APPLY(JSTypedArray); case JS_EXTERNAL_OBJECT_TYPE: return CALL_APPLY(JSExternalObject); case WEAK_CELL_TYPE: return CALL_APPLY(WeakCell); case JS_WEAK_REF_TYPE: return CALL_APPLY(JSWeakRef); case JS_PROXY_TYPE: return CALL_APPLY(JSProxy); case FOREIGN_TYPE: return CALL_APPLY(Foreign); case MAP_TYPE: return CALL_APPLY(Map); case CODE_TYPE: return CALL_APPLY(Code); case CELL_TYPE: return CALL_APPLY(Cell); case PROPERTY_CELL_TYPE: return CALL_APPLY(PropertyCell); case SYMBOL_TYPE: return CALL_APPLY(Symbol); case BYTECODE_ARRAY_TYPE: return CALL_APPLY(BytecodeArray); case SMALL_ORDERED_HASH_SET_TYPE: return CALL_APPLY(SmallOrderedHashTable<SmallOrderedHashSet>); case SMALL_ORDERED_HASH_MAP_TYPE: return CALL_APPLY(SmallOrderedHashTable<SmallOrderedHashMap>); case SMALL_ORDERED_NAME_DICTIONARY_TYPE: return CALL_APPLY(SmallOrderedHashTable<SmallOrderedNameDictionary>); case SWISS_NAME_DICTIONARY_TYPE: return CALL_APPLY(SwissNameDictionary); case CODE_DATA_CONTAINER_TYPE: return CALL_APPLY(CodeDataContainer); case PREPARSE_DATA_TYPE: return CALL_APPLY(PreparseData); case HEAP_NUMBER_TYPE: return CALL_APPLY(HeapNumber); case BYTE_ARRAY_TYPE: return CALL_APPLY(ByteArray); case BIGINT_TYPE: return CALL_APPLY(BigInt); case ALLOCATION_SITE_TYPE: return CALL_APPLY(AllocationSite); case ODDBALL_TYPE: return CALL_APPLY(Oddball); #define MAKE_STRUCT_CASE(TYPE, Name, name) \ case TYPE: \ return CALL_APPLY(Name); STRUCT_LIST(MAKE_STRUCT_CASE) #undef MAKE_STRUCT_CASE case CALL_HANDLER_INFO_TYPE: return CALL_APPLY(CallHandlerInfo); case LOAD_HANDLER_TYPE: return CALL_APPLY(LoadHandler); case STORE_HANDLER_TYPE: return CALL_APPLY(StoreHandler); case SOURCE_TEXT_MODULE_TYPE: return CALL_APPLY(SourceTextModule); case SYNTHETIC_MODULE_TYPE: return CALL_APPLY(SyntheticModule); // TODO(turbofan): Avoid duplicated cases when the body descriptors are // identical. #define MAKE_TORQUE_BODY_DESCRIPTOR_APPLY(TYPE, TypeName) \ case TYPE: \ return CALL_APPLY(TypeName); TORQUE_INSTANCE_TYPE_TO_BODY_DESCRIPTOR_LIST( MAKE_TORQUE_BODY_DESCRIPTOR_APPLY) #undef MAKE_TORQUE_BODY_DESCRIPTOR_APPLY case FILLER_TYPE: return Op::template apply<FreeSpaceFillerBodyDescriptor>( std::forward<Args>(args)...); case FREE_SPACE_TYPE: return CALL_APPLY(FreeSpace); default: PrintF("Unknown type: %d\n", type); UNREACHABLE(); } #undef CALL_APPLY } template <typename ObjectVisitor> void HeapObject::IterateFast(PtrComprCageBase cage_base, ObjectVisitor* v) { v->VisitMapPointer(*this); IterateBodyFast(cage_base, v); } template <typename ObjectVisitor> void HeapObject::IterateFast(Map map, int object_size, ObjectVisitor* v) { v->VisitMapPointer(*this); IterateBodyFast(map, object_size, v); } template <typename ObjectVisitor> void HeapObject::IterateBodyFast(PtrComprCageBase cage_base, ObjectVisitor* v) { Map m = map(cage_base); 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>(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); for (InternalIndex i : table.IterateEntries()) { const int key_index = EphemeronHashTable::EntryToIndex(i); const int value_index = EphemeronHashTable::EntryToValueIndex(i); IterateEphemeron(obj, i.as_int(), OffsetOfElementAt(key_index), OffsetOfElementAt(value_index), v); } } static inline int SizeOf(Map map, HeapObject object) { return object.SizeFromMap(map); } }; #include "torque-generated/objects-body-descriptors-inl.inc" } // namespace internal } // namespace v8 #endif // V8_OBJECTS_OBJECTS_BODY_DESCRIPTORS_INL_H_