blob: a7571ae288a23792ad2c85282923c9317287731c [file] [log] [blame]
// 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/objects/arguments-inl.h"
#include "src/objects/cell.h"
#include "src/objects/data-handler.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/objects-body-descriptors.h"
#include "src/objects/oddball.h"
#include "src/objects/ordered-hash-table-inl.h"
#include "src/objects/source-text-module.h"
#include "src/objects/synthetic-module.h"
#include "src/objects/torque-defined-classes-inl.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);
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 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 Derived::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 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 == 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()));
}
static inline int SizeOf(Map map, HeapObject object) { return kSize; }
};
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, kParentOffset, v);
IteratePointer(obj, kSubtypesOffset, v);
}
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 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 ==
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 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 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 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) {
if (!WasmArray::type(map)->element_type().is_reference_type()) 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);
wasm::StructType* type = WasmStruct::GcSafeType(map);
for (uint32_t i = 0; i < type->field_count(); i++) {
if (!type->field(i).is_reference_type()) 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 map.instance_size();
}
};
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 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 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 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 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 COVERAGE_INFO_TYPE:
return Op::template apply<CoverageInfo::BodyDescriptor>(p1, p2, p3, p4);
case WASM_ARRAY_TYPE:
return Op::template apply<WasmArray::BodyDescriptor>(p1, p2, p3, p4);
case WASM_STRUCT_TYPE:
return Op::template apply<WasmStruct::BodyDescriptor>(p1, p2, p3, p4);
case WASM_TYPE_INFO_TYPE:
return Op::template apply<WasmTypeInfo::BodyDescriptor>(p1, p2, p3, p4);
case JS_OBJECT_TYPE:
case JS_ERROR_TYPE:
case JS_ARGUMENTS_OBJECT_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_PRIMITIVE_WRAPPER_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_REG_EXP_STRING_ITERATOR_TYPE:
case JS_REG_EXP_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_REGISTRY_TYPE:
#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
case WASM_EXCEPTION_OBJECT_TYPE:
case WASM_GLOBAL_OBJECT_TYPE:
case WASM_MEMORY_OBJECT_TYPE:
case WASM_MODULE_OBJECT_TYPE:
case WASM_TABLE_OBJECT_TYPE:
return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3, p4);
case WASM_INSTANCE_OBJECT_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 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 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 if (type == WASM_INDIRECT_FUNCTION_TABLE_TYPE) {
return Op::template apply<WasmIndirectFunctionTable::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);
case SOURCE_TEXT_MODULE_TYPE:
return Op::template apply<SourceTextModule::BodyDescriptor>(p1, p2, p3,
p4);
case SYNTHETIC_MODULE_TYPE:
return Op::template apply<SyntheticModule::BodyDescriptor>(p1, p2, p3,
p4);
// TODO(tebbi): Avoid duplicated cases when the body descriptors are identical.
#define MAKE_TORQUE_BODY_DESCRIPTOR_APPLY(TYPE, TypeName) \
case TYPE: \
return Op::template apply<TypeName::BodyDescriptor>(p1, p2, p3, p4);
TORQUE_INSTANCE_TYPE_TO_BODY_DESCRIPTOR_LIST(
MAKE_TORQUE_BODY_DESCRIPTOR_APPLY)
#undef MAKE_TORQUE_BODY_DESCRIPTOR_APPLY
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);
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_