| // Copyright 2018 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_SNAPSHOT_REFERENCES_H_ |
| #define V8_SNAPSHOT_REFERENCES_H_ |
| |
| #include "src/base/hashmap.h" |
| #include "src/common/assert-scope.h" |
| #include "src/utils/utils.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // TODO(goszczycki): Move this somewhere every file in src/snapshot can use it. |
| // The spaces suported by the serializer. Spaces after LO_SPACE (NEW_LO_SPACE |
| // and CODE_LO_SPACE) are not supported. |
| enum class SnapshotSpace { |
| kReadOnlyHeap = RO_SPACE, |
| kNew = NEW_SPACE, |
| kOld = OLD_SPACE, |
| kCode = CODE_SPACE, |
| kMap = MAP_SPACE, |
| kLargeObject = LO_SPACE, |
| kNumberOfPreallocatedSpaces = kCode + 1, |
| kNumberOfSpaces = kLargeObject + 1, |
| kSpecialValueSpace = kNumberOfSpaces, |
| // Number of spaces which should be allocated by the heap. Eventually |
| // kReadOnlyHeap will move to the end of this enum and this will be equal to |
| // it. |
| kNumberOfHeapSpaces = kNumberOfSpaces, |
| }; |
| |
| constexpr bool IsPreAllocatedSpace(SnapshotSpace space) { |
| return static_cast<int>(space) < |
| static_cast<int>(SnapshotSpace::kNumberOfPreallocatedSpaces); |
| } |
| |
| class SerializerReference { |
| private: |
| enum SpecialValueType { |
| kInvalidValue, |
| kAttachedReference, |
| kOffHeapBackingStore, |
| kBuiltinReference, |
| }; |
| |
| STATIC_ASSERT(static_cast<int>(SnapshotSpace::kSpecialValueSpace) < |
| (1 << kSpaceTagSize)); |
| |
| SerializerReference(SpecialValueType type, uint32_t value) |
| : bitfield_(SpaceBits::encode(SnapshotSpace::kSpecialValueSpace) | |
| SpecialValueTypeBits::encode(type)), |
| value_(value) {} |
| |
| public: |
| SerializerReference() : SerializerReference(kInvalidValue, 0) {} |
| |
| SerializerReference(SnapshotSpace space, uint32_t chunk_index, |
| uint32_t chunk_offset) |
| : bitfield_(SpaceBits::encode(space) | |
| ChunkIndexBits::encode(chunk_index)), |
| value_(chunk_offset) {} |
| |
| static SerializerReference BackReference(SnapshotSpace space, |
| uint32_t chunk_index, |
| uint32_t chunk_offset) { |
| DCHECK(IsAligned(chunk_offset, kObjectAlignment)); |
| return SerializerReference(space, chunk_index, chunk_offset); |
| } |
| |
| static SerializerReference MapReference(uint32_t index) { |
| return SerializerReference(SnapshotSpace::kMap, 0, index); |
| } |
| |
| static SerializerReference OffHeapBackingStoreReference(uint32_t index) { |
| return SerializerReference(kOffHeapBackingStore, index); |
| } |
| |
| static SerializerReference LargeObjectReference(uint32_t index) { |
| return SerializerReference(SnapshotSpace::kLargeObject, 0, index); |
| } |
| |
| static SerializerReference AttachedReference(uint32_t index) { |
| return SerializerReference(kAttachedReference, index); |
| } |
| |
| static SerializerReference BuiltinReference(uint32_t index) { |
| return SerializerReference(kBuiltinReference, index); |
| } |
| |
| bool is_valid() const { |
| return SpaceBits::decode(bitfield_) != SnapshotSpace::kSpecialValueSpace || |
| SpecialValueTypeBits::decode(bitfield_) != kInvalidValue; |
| } |
| |
| bool is_back_reference() const { |
| return SpaceBits::decode(bitfield_) != SnapshotSpace::kSpecialValueSpace; |
| } |
| |
| SnapshotSpace space() const { |
| DCHECK(is_back_reference()); |
| return SpaceBits::decode(bitfield_); |
| } |
| |
| uint32_t chunk_offset() const { |
| DCHECK(is_back_reference()); |
| return value_; |
| } |
| |
| uint32_t chunk_index() const { |
| DCHECK(IsPreAllocatedSpace(space())); |
| return ChunkIndexBits::decode(bitfield_); |
| } |
| |
| uint32_t map_index() const { |
| DCHECK_EQ(SnapshotSpace::kMap, SpaceBits::decode(bitfield_)); |
| return value_; |
| } |
| |
| bool is_off_heap_backing_store_reference() const { |
| return SpaceBits::decode(bitfield_) == SnapshotSpace::kSpecialValueSpace && |
| SpecialValueTypeBits::decode(bitfield_) == kOffHeapBackingStore; |
| } |
| |
| uint32_t off_heap_backing_store_index() const { |
| DCHECK(is_off_heap_backing_store_reference()); |
| return value_; |
| } |
| |
| uint32_t large_object_index() const { |
| DCHECK_EQ(SnapshotSpace::kLargeObject, SpaceBits::decode(bitfield_)); |
| return value_; |
| } |
| |
| bool is_attached_reference() const { |
| return SpaceBits::decode(bitfield_) == SnapshotSpace::kSpecialValueSpace && |
| SpecialValueTypeBits::decode(bitfield_) == kAttachedReference; |
| } |
| |
| uint32_t attached_reference_index() const { |
| DCHECK(is_attached_reference()); |
| return value_; |
| } |
| |
| bool is_builtin_reference() const { |
| return SpaceBits::decode(bitfield_) == SnapshotSpace::kSpecialValueSpace && |
| SpecialValueTypeBits::decode(bitfield_) == kBuiltinReference; |
| } |
| |
| uint32_t builtin_index() const { |
| DCHECK(is_builtin_reference()); |
| return value_; |
| } |
| |
| private: |
| class SpaceBits : public BitField<SnapshotSpace, 0, kSpaceTagSize> {}; |
| class ChunkIndexBits |
| : public BitField<uint32_t, SpaceBits::kNext, 32 - kSpaceTagSize> {}; |
| class SpecialValueTypeBits |
| : public BitField<SpecialValueType, SpaceBits::kNext, |
| 32 - kSpaceTagSize> {}; |
| |
| // We use two fields to store a reference. |
| // In case of a normal back reference, the bitfield_ stores the space and |
| // the chunk index. In case of special references, it uses a special value |
| // for space and stores the special value type. |
| uint32_t bitfield_; |
| // value_ stores either chunk offset or special value. |
| uint32_t value_; |
| |
| friend class SerializerReferenceMap; |
| }; |
| |
| class SerializerReferenceMap |
| : public base::TemplateHashMapImpl<uintptr_t, SerializerReference, |
| base::KeyEqualityMatcher<intptr_t>, |
| base::DefaultAllocationPolicy> { |
| public: |
| using Entry = base::TemplateHashMapEntry<uintptr_t, SerializerReference>; |
| |
| SerializerReferenceMap() : attached_reference_index_(0) {} |
| |
| SerializerReference LookupReference(void* value) const { |
| uintptr_t key = Key(value); |
| Entry* entry = Lookup(key, Hash(key)); |
| if (entry == nullptr) return SerializerReference(); |
| return entry->value; |
| } |
| |
| void Add(void* obj, SerializerReference reference) { |
| DCHECK(reference.is_valid()); |
| DCHECK(!LookupReference(obj).is_valid()); |
| uintptr_t key = Key(obj); |
| LookupOrInsert(key, Hash(key))->value = reference; |
| } |
| |
| SerializerReference AddAttachedReference(void* attached_reference) { |
| SerializerReference reference = |
| SerializerReference::AttachedReference(attached_reference_index_++); |
| Add(attached_reference, reference); |
| return reference; |
| } |
| |
| private: |
| static inline uintptr_t Key(void* value) { |
| return reinterpret_cast<uintptr_t>(value); |
| } |
| |
| static uint32_t Hash(uintptr_t key) { return static_cast<uint32_t>(key); } |
| |
| DISALLOW_HEAP_ALLOCATION(no_allocation_) |
| int attached_reference_index_; |
| DISALLOW_COPY_AND_ASSIGN(SerializerReferenceMap); |
| }; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_SNAPSHOT_REFERENCES_H_ |