From b0dc290a9a02085012ab96d3a58b05d800b06f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= Date: Mon, 12 Mar 2018 11:26:53 +0100 Subject: [PATCH] [in-place weak refs] Add WeakFixedArray (an array of in-place weak references). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not used yet apart from tests. BUG=v8:7308 Change-Id: Ibbe12597007cba123236c9fab85c524df3d5dd4a Reviewed-on: https://chromium-review.googlesource.com/955427 Commit-Queue: Marja Hölttä Reviewed-by: Ulan Degenbaev Reviewed-by: Hannes Payer Cr-Commit-Position: refs/heads/master@{#51876} --- src/compiler/types.cc | 1 + src/factory.cc | 10 ++ src/factory.h | 6 + src/heap/heap-inl.h | 36 ++++++ src/heap/heap.cc | 19 ++- src/heap/heap.h | 25 +++- src/heap/mark-compact.cc | 4 +- src/heap/objects-visiting.h | 3 +- src/heap/setup-heap-internal.cc | 9 ++ src/objects-body-descriptors-inl.h | 26 ++++ src/objects-body-descriptors.h | 4 + src/objects-debug.cc | 9 ++ src/objects-inl.h | 4 + src/objects.cc | 3 + src/objects.h | 5 +- src/objects/fixed-array-inl.h | 23 +++- src/objects/fixed-array.h | 48 ++++++++ src/objects/map.h | 3 +- src/objects/object-macros.h | 10 ++ src/profiler/heap-snapshot-generator.cc | 1 + test/cctest/heap/test-weak-references.cc | 80 +++++++++++++ tools/v8heapconst.py | 144 ++++++++++++----------- 22 files changed, 388 insertions(+), 85 deletions(-) diff --git a/src/compiler/types.cc b/src/compiler/types.cc index 20f80f6413..3cb2d30659 100644 --- a/src/compiler/types.cc +++ b/src/compiler/types.cc @@ -264,6 +264,7 @@ Type::bitset BitsetType::Lub(i::Map* map) { case ACCESSOR_PAIR_TYPE: case FIXED_ARRAY_TYPE: case HASH_TABLE_TYPE: + case WEAK_FIXED_ARRAY_TYPE: case FIXED_DOUBLE_ARRAY_TYPE: case FEEDBACK_METADATA_TYPE: case BYTE_ARRAY_TYPE: diff --git a/src/factory.cc b/src/factory.cc index 037e5c273c..516ef752da 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -203,6 +203,16 @@ Handle Factory::NewFixedArray(int length, PretenureFlag pretenure) { FixedArray); } +Handle Factory::NewWeakFixedArray(int length, + PretenureFlag pretenure) { + DCHECK_LE(0, length); + if (length == 0) return empty_weak_fixed_array(); + + CALL_HEAP_FUNCTION( + isolate(), isolate()->heap()->AllocateWeakFixedArray(length, pretenure), + WeakFixedArray); +} + MaybeHandle Factory::TryNewFixedArray(int length, PretenureFlag pretenure) { DCHECK_LE(0, length); diff --git a/src/factory.h b/src/factory.h index 0b12d5a678..4d99d7a481 100644 --- a/src/factory.h +++ b/src/factory.h @@ -96,6 +96,12 @@ class V8_EXPORT_PRIVATE Factory final { // Allocates a fixed array initialized with undefined values. Handle NewFixedArray(int length, PretenureFlag pretenure = NOT_TENURED); + + // Allocates a fixed array which may contain in-place weak references. The + // array is initialized with undefined values + Handle NewWeakFixedArray( + int length, PretenureFlag pretenure = NOT_TENURED); + Handle NewPropertyArray(int length, PretenureFlag pretenure = NOT_TENURED); // Tries allocating a fixed array initialized with undefined values. diff --git a/src/heap/heap-inl.h b/src/heap/heap-inl.h index a09129dfd5..2e1ff865ca 100644 --- a/src/heap/heap-inl.h +++ b/src/heap/heap-inl.h @@ -247,6 +247,42 @@ AllocationResult Heap::AllocateFixedArray(int length, PretenureFlag pretenure) { pretenure, undefined_value()); } +AllocationResult Heap::AllocateWeakFixedArray(int length, + PretenureFlag pretenure) { + // Zero-length case must be handled outside, where the knowledge about + // the map is. + DCHECK_LT(0, length); + HeapObject* result = nullptr; + { + AllocationResult allocation = AllocateRawWeakFixedArray(length, pretenure); + if (!allocation.To(&result)) return allocation; + } + DCHECK(RootIsImmortalImmovable(Heap::kWeakFixedArrayMapRootIndex)); + Map* map = Map::cast(root(Heap::kWeakFixedArrayMapRootIndex)); + result->set_map_after_allocation(map, SKIP_WRITE_BARRIER); + WeakFixedArray* array = WeakFixedArray::cast(result); + array->set_length(length); + MemsetPointer(array->data_start(), + HeapObjectReference::Strong(undefined_value()), length); + return array; +} + +AllocationResult Heap::AllocateRawFixedArray(int length, + PretenureFlag pretenure) { + if (length < 0 || length > FixedArray::kMaxLength) { + v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); + } + return AllocateRawArray(FixedArray::SizeFor(length), pretenure); +} + +AllocationResult Heap::AllocateRawWeakFixedArray(int length, + PretenureFlag pretenure) { + if (length < 0 || length > WeakFixedArray::kMaxLength) { + v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); + } + return AllocateRawArray(WeakFixedArray::SizeFor(length), pretenure); +} + AllocationResult Heap::AllocateRaw(int size_in_bytes, AllocationSpace space, AllocationAlignment alignment) { DCHECK(AllowHandleAllocation::IsAllowed()); diff --git a/src/heap/heap.cc b/src/heap/heap.cc index de11a7959f..417b41944f 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -3763,6 +3763,18 @@ AllocationResult Heap::AllocateEmptyFixedArray() { return result; } +AllocationResult Heap::AllocateEmptyWeakFixedArray() { + int size = WeakFixedArray::SizeFor(0); + HeapObject* result = nullptr; + { + AllocationResult allocation = AllocateRaw(size, OLD_SPACE); + if (!allocation.To(&result)) return allocation; + } + result->set_map_after_allocation(weak_fixed_array_map(), SKIP_WRITE_BARRIER); + WeakFixedArray::cast(result)->set_length(0); + return result; +} + AllocationResult Heap::AllocateEmptyScopeInfo() { int size = FixedArray::SizeFor(0); HeapObject* result = nullptr; @@ -3975,12 +3987,7 @@ AllocationResult Heap::CopyFeedbackVector(FeedbackVector* src) { return result; } -AllocationResult Heap::AllocateRawFixedArray(int length, - PretenureFlag pretenure) { - if (length < 0 || length > FixedArray::kMaxLength) { - v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true); - } - int size = FixedArray::SizeFor(length); +AllocationResult Heap::AllocateRawArray(int size, PretenureFlag pretenure) { AllocationSpace space = SelectSpace(pretenure); AllocationResult result = AllocateRaw(size, space); diff --git a/src/heap/heap.h b/src/heap/heap.h index 832cb96273..d656fa7784 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -133,6 +133,7 @@ using v8::MemoryPressureLevel; V(Map, small_ordered_hash_map_map, SmallOrderedHashMapMap) \ V(Map, small_ordered_hash_set_map, SmallOrderedHashSetMap) \ V(Map, string_table_map, StringTableMap) \ + V(Map, weak_fixed_array_map, WeakFixedArrayMap) \ V(Map, weak_hash_table_map, WeakHashTableMap) \ /* String maps */ \ V(Map, native_source_string_map, NativeSourceStringMap) \ @@ -217,6 +218,7 @@ using v8::MemoryPressureLevel; V(WeakCell, empty_weak_cell, EmptyWeakCell) \ V(Cell, invalid_prototype_validity_cell, InvalidPrototypeValidityCell) \ V(InterceptorInfo, noop_interceptor_info, NoOpInterceptorInfo) \ + V(WeakFixedArray, empty_weak_fixed_array, EmptyWeakFixedArray) \ /* Protectors */ \ V(Cell, array_constructor_protector, ArrayConstructorProtector) \ V(PropertyCell, no_elements_protector, NoElementsProtector) \ @@ -403,6 +405,7 @@ using v8::MemoryPressureLevel; V(UninitializedMap) \ V(UninitializedValue) \ V(WeakCellMap) \ + V(WeakFixedArrayMap) \ V(WeakHashTableMap) \ V(WithContextMap) \ V(empty_string) \ @@ -2159,6 +2162,19 @@ class Heap { MUST_USE_RESULT inline AllocationResult AllocateFixedArray( int length, PretenureFlag pretenure = NOT_TENURED); + // Allocates an array allowing in-place weak references, initialized with + // undefined values + MUST_USE_RESULT inline AllocationResult AllocateWeakFixedArray( + int length, PretenureFlag pretenure = NOT_TENURED); + + // Allocate memory for an uninitialized FixedArray. + MUST_USE_RESULT inline AllocationResult AllocateRawFixedArray( + int length, PretenureFlag pretenure); + + // Allocate memory for an uninitialized WeakFixedArray. + MUST_USE_RESULT inline AllocationResult AllocateRawWeakFixedArray( + int length, PretenureFlag pretenure); + // Allocates a property array initialized with undefined values MUST_USE_RESULT AllocationResult AllocatePropertyArray(int length, PretenureFlag pretenure = NOT_TENURED); @@ -2199,9 +2215,9 @@ class Heap { MUST_USE_RESULT AllocationResult AllocateFillerObject(int size, bool double_align, AllocationSpace space); - // Allocate an uninitialized fixed array. - MUST_USE_RESULT AllocationResult - AllocateRawFixedArray(int length, PretenureFlag pretenure); + // Allocate memory for an uninitialized array (e.g., a FixedArray or similar). + MUST_USE_RESULT AllocationResult AllocateRawArray(int size, + PretenureFlag pretenure); // Allocate an uninitialized fixed double array. MUST_USE_RESULT AllocationResult @@ -2313,6 +2329,9 @@ class Heap { // Allocate empty fixed array like objects. MUST_USE_RESULT AllocationResult AllocateEmptyFixedArray(); + + MUST_USE_RESULT AllocationResult AllocateEmptyWeakFixedArray(); + MUST_USE_RESULT AllocationResult AllocateEmptyScopeInfo(); MUST_USE_RESULT AllocationResult AllocateEmptyBoilerplateDescription(); diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc index 6d0d583305..9f9a08dfd0 100644 --- a/src/heap/mark-compact.cc +++ b/src/heap/mark-compact.cc @@ -3033,7 +3033,9 @@ class PointersUpdatingVisitor : public ObjectVisitor, public RootVisitor { void VisitPointers(HeapObject* host, MaybeObject** start, MaybeObject** end) final { - UNREACHABLE(); + for (MaybeObject** p = start; p < end; p++) { + UpdateSlotInternal(p); + } } void VisitRootPointer(Root root, const char* description, diff --git a/src/heap/objects-visiting.h b/src/heap/objects-visiting.h index 7746c91c71..4dbfa10ae0 100644 --- a/src/heap/objects-visiting.h +++ b/src/heap/objects-visiting.h @@ -55,7 +55,8 @@ class JSWeakCollection; V(Symbol) \ V(ThinString) \ V(TransitionArray) \ - V(WeakCell) + V(WeakCell) \ + V(WeakFixedArray) // The base class for visitors that need to dispatch on object type. The default // behavior of all visit functions is to iterate body of the given object using diff --git a/src/heap/setup-heap-internal.cc b/src/heap/setup-heap-internal.cc index 2c3ebe2f3d..f9932735c5 100644 --- a/src/heap/setup-heap-internal.cc +++ b/src/heap/setup-heap-internal.cc @@ -113,6 +113,8 @@ bool Heap::CreateInitialMaps() { } ALLOCATE_PARTIAL_MAP(FIXED_ARRAY_TYPE, kVariableSizeSentinel, fixed_array); + ALLOCATE_PARTIAL_MAP(WEAK_FIXED_ARRAY_TYPE, kVariableSizeSentinel, + weak_fixed_array); ALLOCATE_PARTIAL_MAP(FIXED_ARRAY_TYPE, kVariableSizeSentinel, fixed_cow_array) DCHECK_NE(fixed_array_map(), fixed_cow_array_map()); @@ -134,6 +136,12 @@ bool Heap::CreateInitialMaps() { } set_empty_fixed_array(FixedArray::cast(obj)); + { + AllocationResult allocation = AllocateEmptyWeakFixedArray(); + if (!allocation.To(&obj)) return false; + } + set_empty_weak_fixed_array(WeakFixedArray::cast(obj)); + { AllocationResult allocation = Allocate(null_map(), OLD_SPACE); if (!allocation.To(&obj)) return false; @@ -192,6 +200,7 @@ bool Heap::CreateInitialMaps() { // Fix the instance_descriptors for the existing maps. FinalizePartialMap(this, meta_map()); FinalizePartialMap(this, fixed_array_map()); + FinalizePartialMap(this, weak_fixed_array_map()); FinalizePartialMap(this, fixed_cow_array_map()); FinalizePartialMap(this, descriptor_array_map()); FinalizePartialMap(this, undefined_map()); diff --git a/src/objects-body-descriptors-inl.h b/src/objects-body-descriptors-inl.h index ea67b3c29e..873f6a5c8f 100644 --- a/src/objects-body-descriptors-inl.h +++ b/src/objects-body-descriptors-inl.h @@ -69,6 +69,13 @@ void BodyDescriptorBase::IteratePointer(HeapObject* obj, int offset, v->VisitPointer(obj, HeapObject::RawField(obj, offset)); } +template +DISABLE_CFI_PERF void BodyDescriptorBase::IterateMaybeWeakPointers( + HeapObject* obj, int start_offset, int end_offset, ObjectVisitor* v) { + v->VisitPointers(obj, HeapObject::RawMaybeWeakField(obj, start_offset), + HeapObject::RawMaybeWeakField(obj, end_offset)); +} + template void BodyDescriptorBase::IterateMaybeWeakPointer(HeapObject* obj, int offset, ObjectVisitor* v) { @@ -268,6 +275,23 @@ class FixedTypedArrayBase::BodyDescriptor final : public BodyDescriptorBase { } }; +class WeakFixedArray::BodyDescriptor final : public BodyDescriptorBase { + public: + static bool IsValidSlot(HeapObject* obj, int offset) { + return offset >= kHeaderSize; + } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + IterateMaybeWeakPointers(obj, kHeaderSize, object_size, v); + } + + static inline int SizeOf(Map* map, HeapObject* object) { + return object->SizeFromMap(map); + } +}; + class FeedbackMetadata::BodyDescriptor final : public BodyDescriptorBase { public: static bool IsValidSlot(HeapObject* obj, int offset) { return false; } @@ -472,6 +496,8 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) { case HASH_TABLE_TYPE: case SCOPE_INFO_TYPE: return Op::template apply(p1, p2, p3); + case WEAK_FIXED_ARRAY_TYPE: + return Op::template apply(p1, p2, p3); case FIXED_DOUBLE_ARRAY_TYPE: return ReturnType(); case FEEDBACK_METADATA_TYPE: diff --git a/src/objects-body-descriptors.h b/src/objects-body-descriptors.h index 15ffb18168..c33676f04c 100644 --- a/src/objects-body-descriptors.h +++ b/src/objects-body-descriptors.h @@ -36,6 +36,10 @@ class BodyDescriptorBase BASE_EMBEDDED { static inline void IteratePointer(HeapObject* obj, int offset, ObjectVisitor* v); + template + static inline void IterateMaybeWeakPointers(HeapObject* obj, int start_offset, + int end_offset, ObjectVisitor* v); + template static inline void IterateMaybeWeakPointer(HeapObject* obj, int offset, ObjectVisitor* v); diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 545b3ac2df..66ab3c514c 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -126,6 +126,9 @@ void HeapObject::HeapObjectVerify() { case SCOPE_INFO_TYPE: FixedArray::cast(this)->FixedArrayVerify(); break; + case WEAK_FIXED_ARRAY_TYPE: + WeakFixedArray::cast(this)->WeakFixedArrayVerify(); + break; case FIXED_DOUBLE_ARRAY_TYPE: FixedDoubleArray::cast(this)->FixedDoubleArrayVerify(); break; @@ -529,6 +532,12 @@ void FixedArray::FixedArrayVerify() { } } +void WeakFixedArray::WeakFixedArrayVerify() { + for (int i = 0; i < length(); i++) { + MaybeObject::VerifyMaybeObjectPointer(Get(i)); + } +} + void PropertyArray::PropertyArrayVerify() { if (length() == 0) { CHECK_EQ(this, this->GetHeap()->empty_property_array()); diff --git a/src/objects-inl.h b/src/objects-inl.h index 7f917edf10..922ab907c7 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2234,6 +2234,10 @@ int HeapObject::SizeFromMap(Map* map) const { reinterpret_cast(this) ->synchronized_slot_count()); } + if (instance_type == WEAK_FIXED_ARRAY_TYPE) { + return WeakFixedArray::SizeFor( + reinterpret_cast(this)->synchronized_length()); + } if (instance_type >= FIRST_FIXED_TYPED_ARRAY_TYPE && instance_type <= LAST_FIXED_TYPED_ARRAY_TYPE) { return reinterpret_cast(this)->TypedArraySize( diff --git a/src/objects.cc b/src/objects.cc index 56781b0702..bdc8a522cf 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -2984,6 +2984,9 @@ VisitorId Map::GetVisitorId(Map* map) { case SCOPE_INFO_TYPE: return kVisitFixedArray; + case WEAK_FIXED_ARRAY_TYPE: + return kVisitWeakFixedArray; + case FIXED_DOUBLE_ARRAY_TYPE: return kVisitFixedDoubleArray; diff --git a/src/objects.h b/src/objects.h index 0906f58303..91869cfb79 100644 --- a/src/objects.h +++ b/src/objects.h @@ -413,6 +413,7 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1; V(SMALL_ORDERED_HASH_SET_TYPE) \ V(STORE_HANDLER_TYPE) \ V(WEAK_CELL_TYPE) \ + V(WEAK_FIXED_ARRAY_TYPE) \ \ V(JS_PROXY_TYPE) \ V(JS_GLOBAL_OBJECT_TYPE) \ @@ -767,6 +768,7 @@ enum InstanceType : uint16_t { SMALL_ORDERED_HASH_SET_TYPE, STORE_HANDLER_TYPE, WEAK_CELL_TYPE, + WEAK_FIXED_ARRAY_TYPE, // All the following types are subtypes of JSReceiver, which corresponds to // objects in the JS sense. The first and the last type in this range are @@ -985,6 +987,7 @@ template inline bool Is(Object* obj); V(FixedArray) \ V(FixedArrayBase) \ V(FixedArrayExact) \ + V(FixedArrayOfWeakCells) \ V(FixedBigInt64Array) \ V(FixedBigUint64Array) \ V(FixedDoubleArray) \ @@ -1097,7 +1100,7 @@ template inline bool Is(Object* obj); V(WasmModuleObject) \ V(WasmTableObject) \ V(WeakCell) \ - V(FixedArrayOfWeakCells) \ + V(WeakFixedArray) \ V(WeakHashTable) #define HEAP_OBJECT_TEMPLATE_TYPE_LIST(V) \ diff --git a/src/objects/fixed-array-inl.h b/src/objects/fixed-array-inl.h index 46b0048a64..8c708f48cf 100644 --- a/src/objects/fixed-array-inl.h +++ b/src/objects/fixed-array-inl.h @@ -17,6 +17,7 @@ TYPE_CHECKER(ByteArray, BYTE_ARRAY_TYPE) TYPE_CHECKER(FixedArrayExact, FIXED_ARRAY_TYPE) TYPE_CHECKER(FixedDoubleArray, FIXED_DOUBLE_ARRAY_TYPE) TYPE_CHECKER(FixedArrayOfWeakCells, FIXED_ARRAY_TYPE) +TYPE_CHECKER(WeakFixedArray, WEAK_FIXED_ARRAY_TYPE) CAST_ACCESSOR(ArrayList) CAST_ACCESSOR(ByteArray) @@ -26,9 +27,12 @@ CAST_ACCESSOR(FixedDoubleArray) CAST_ACCESSOR(FixedTypedArrayBase) CAST_ACCESSOR(TemplateList) CAST_ACCESSOR(FixedArrayOfWeakCells) +CAST_ACCESSOR(WeakFixedArray) SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset) SYNCHRONIZED_SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset) +SMI_ACCESSORS(WeakFixedArray, length, kLengthOffset) +SYNCHRONIZED_SMI_ACCESSORS(WeakFixedArray, length, kLengthOffset) Object* FixedArrayBase::unchecked_synchronized_length() const { return ACQUIRE_READ_FIELD(this, kLengthOffset); @@ -142,7 +146,7 @@ void FixedArray::FillWithHoles(int from, int to) { } Object** FixedArray::data_start() { - return HeapObject::RawField(this, kHeaderSize); + return HeapObject::RawField(this, OffsetOfElementAt(0)); } Object** FixedArray::RawFieldOfElementAt(int index) { @@ -215,6 +219,23 @@ void FixedDoubleArray::FillWithHoles(int from, int to) { } } +MaybeObject* WeakFixedArray::Get(int index) const { + SLOW_DCHECK(index >= 0 && index < this->length()); + return RELAXED_READ_WEAK_FIELD(this, OffsetOfElementAt(index)); +} + +void WeakFixedArray::Set(int index, MaybeObject* value) { + DCHECK_GE(index, 0); + DCHECK_LT(index, length()); + int offset = OffsetOfElementAt(index); + RELAXED_WRITE_FIELD(this, offset, value); + WEAK_WRITE_BARRIER(GetHeap(), this, offset, value); +} + +MaybeObject** WeakFixedArray::data_start() { + return HeapObject::RawMaybeWeakField(this, kHeaderSize); +} + Object* FixedArrayOfWeakCells::Get(int index) const { Object* raw = FixedArray::cast(this)->get(index + kFirstIndex); if (raw->IsSmi()) return raw; diff --git a/src/objects/fixed-array.h b/src/objects/fixed-array.h index 6b2b2c0191..0c53b2e8ba 100644 --- a/src/objects/fixed-array.h +++ b/src/objects/fixed-array.h @@ -243,6 +243,54 @@ class FixedDoubleArray : public FixedArrayBase { DISALLOW_IMPLICIT_CONSTRUCTORS(FixedDoubleArray); }; +// WeakFixedArray describes fixed-sized arrays with element type +// MaybeObject*. +class WeakFixedArray : public HeapObject { + public: + DECL_CAST(WeakFixedArray) + + inline MaybeObject* Get(int index) const; + + // Setter that uses write barrier. + inline void Set(int index, MaybeObject* value); + + static constexpr int SizeFor(int length) { + return kHeaderSize + length * kPointerSize; + } + + DECL_INT_ACCESSORS(length) + + // Get and set the length using acquire loads and release stores. + inline int synchronized_length() const; + inline void synchronized_set_length(int value); + + // Gives access to raw memory which stores the array's data. + inline MaybeObject** data_start(); + + DECL_VERIFIER(WeakFixedArray) + + class BodyDescriptor; + typedef BodyDescriptor BodyDescriptorWeak; + + static const int kLengthOffset = HeapObject::kHeaderSize; + static const int kHeaderSize = kLengthOffset + kPointerSize; + + static const int kMaxLength = + (FixedArray::kMaxSize - kHeaderSize) / kPointerSize; + + private: + static int OffsetOfElementAt(int index) { + return kHeaderSize + index * kPointerSize; + } + + friend class Heap; + + static const int kFirstIndex = 1; + + DISALLOW_IMPLICIT_CONSTRUCTORS(WeakFixedArray); +}; + +// Deprecated. Use WeakFixedArray instead. class FixedArrayOfWeakCells : public FixedArray { public: // If |maybe_array| is not a FixedArrayOfWeakCells, a fresh one will be diff --git a/src/objects/map.h b/src/objects/map.h index 7b494db469..747611ca0d 100644 --- a/src/objects/map.h +++ b/src/objects/map.h @@ -56,7 +56,8 @@ namespace internal { V(Symbol) \ V(ThinString) \ V(TransitionArray) \ - V(WeakCell) + V(WeakCell) \ + V(WeakFixedArray) // For data objects, JS objects and structs along with generic visitor which // can visit object of any size we provide visitors specialized by diff --git a/src/objects/object-macros.h b/src/objects/object-macros.h index c15e930575..03a1196703 100644 --- a/src/objects/object-macros.h +++ b/src/objects/object-macros.h @@ -165,6 +165,10 @@ reinterpret_cast(base::Relaxed_Load( \ reinterpret_cast(FIELD_ADDR_CONST(p, offset)))) +#define RELAXED_READ_WEAK_FIELD(p, offset) \ + reinterpret_cast(base::Relaxed_Load( \ + reinterpret_cast(FIELD_ADDR_CONST(p, offset)))) + #ifdef V8_CONCURRENT_MARKING #define WRITE_FIELD(p, offset, value) \ base::Relaxed_Store( \ @@ -196,6 +200,12 @@ object, HeapObject::RawField(object, offset), value); \ heap->RecordWrite(object, HeapObject::RawField(object, offset), value); +#define WEAK_WRITE_BARRIER(heap, object, offset, value) \ + heap->incremental_marking()->RecordMaybeWeakWrite( \ + object, HeapObject::RawMaybeWeakField(object, offset), value); \ + heap->RecordWrite(object, HeapObject::RawMaybeWeakField(object, offset), \ + value); + #define CONDITIONAL_WRITE_BARRIER(heap, object, offset, value, mode) \ if (mode != SKIP_WRITE_BARRIER) { \ if (mode == UPDATE_WRITE_BARRIER) { \ diff --git a/src/profiler/heap-snapshot-generator.cc b/src/profiler/heap-snapshot-generator.cc index 0654f05c41..df73c56295 100644 --- a/src/profiler/heap-snapshot-generator.cc +++ b/src/profiler/heap-snapshot-generator.cc @@ -1625,6 +1625,7 @@ bool V8HeapExplorer::IsEssentialObject(Object* object) { return object->IsHeapObject() && !object->IsOddball() && object != heap_->empty_byte_array() && object != heap_->empty_fixed_array() && + object != heap_->empty_weak_fixed_array() && object != heap_->empty_descriptor_array() && object != heap_->fixed_array_map() && object != heap_->cell_map() && object != heap_->global_property_cell_map() && diff --git a/test/cctest/heap/test-weak-references.cc b/test/cctest/heap/test-weak-references.cc index 9c26939177..eaffa9ced7 100644 --- a/test/cctest/heap/test-weak-references.cc +++ b/test/cctest/heap/test-weak-references.cc @@ -307,6 +307,86 @@ TEST(WeakReferenceWriteBarrier) { CHECK(fv->optimized_code_weak_or_smi()->IsWeakHeapObject()); } +TEST(EmptyWeakArray) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + HandleScope outer_scope(isolate); + + Handle array = factory->empty_weak_fixed_array(); + CHECK(array->IsWeakFixedArray()); + CHECK(!array->IsFixedArray()); + CHECK_EQ(array->length(), 0); +} + +TEST(WeakArraysBasic) { + ManualGCScope manual_gc_scope; + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + Factory* factory = isolate->factory(); + Heap* heap = isolate->heap(); + HandleScope outer_scope(isolate); + + const int length = 4; + Handle array = factory->NewWeakFixedArray(length); + CHECK(array->IsWeakFixedArray()); + CHECK(!array->IsFixedArray()); + CHECK_EQ(array->length(), length); + CHECK(heap->InNewSpace(*array)); + + for (int i = 0; i < length; ++i) { + HeapObject* heap_object; + CHECK(array->Get(i)->ToStrongHeapObject(&heap_object)); + CHECK_EQ(heap_object, heap->undefined_value()); + } + + Handle saved; + { + HandleScope inner_scope(isolate); + Handle index0 = factory->NewFixedArray(1); + index0->set(0, Smi::FromInt(2016)); + Handle index1 = factory->NewFixedArray(1); + index1->set(0, Smi::FromInt(2017)); + + Handle index2 = factory->NewFixedArray(1); + index2->set(0, Smi::FromInt(2018)); + Handle index3 = factory->NewFixedArray(1); + index3->set(0, Smi::FromInt(2019)); + + array->Set(0, HeapObjectReference::Weak(*index0)); + array->Set(1, HeapObjectReference::Weak(*index1)); + array->Set(2, HeapObjectReference::Strong(*index2)); + array->Set(3, HeapObjectReference::Weak(*index3)); + saved = inner_scope.CloseAndEscape(index1); + } // inner_scope goes out of scope. + + // The references are only cleared by the mark-compact (scavenger treats weak + // references as strong). Thus we need to GC until the array reaches old + // space. + + // TODO(marja): update this when/if we do handle weak references in the new + // space. + CcTest::CollectGarbage(NEW_SPACE); + HeapObject* heap_object; + CHECK(array->Get(0)->ToWeakHeapObject(&heap_object)); + CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2016); + CHECK(array->Get(1)->ToWeakHeapObject(&heap_object)); + CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017); + CHECK(array->Get(2)->ToStrongHeapObject(&heap_object)); + CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2018); + CHECK(array->Get(3)->ToWeakHeapObject(&heap_object)); + CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2019); + + CcTest::CollectAllGarbage(); + CHECK(heap->InOldSpace(*array)); + CHECK(array->Get(0)->IsClearedWeakHeapObject()); + CHECK(array->Get(1)->ToWeakHeapObject(&heap_object)); + CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2017); + CHECK(array->Get(2)->ToStrongHeapObject(&heap_object)); + CHECK_EQ(Smi::cast(FixedArray::cast(heap_object)->get(0))->value(), 2018); + CHECK(array->Get(3)->IsClearedWeakHeapObject()); +} + } // namespace heap } // namespace internal } // namespace v8 diff --git a/tools/v8heapconst.py b/tools/v8heapconst.py index ba520e51f3..a6fe6b018c 100644 --- a/tools/v8heapconst.py +++ b/tools/v8heapconst.py @@ -101,6 +101,7 @@ INSTANCE_TYPES = { 197: "SMALL_ORDERED_HASH_SET_TYPE", 198: "STORE_HANDLER_TYPE", 199: "WEAK_CELL_TYPE", + 200: "WEAK_FIXED_ARRAY_TYPE", 1024: "JS_PROXY_TYPE", 1025: "JS_GLOBAL_OBJECT_TYPE", 1026: "JS_GLOBAL_PROXY_TYPE", @@ -211,68 +212,69 @@ KNOWN_MAPS = { 0x03801: (196, "SmallOrderedHashMapMap"), 0x03859: (197, "SmallOrderedHashSetMap"), 0x038b1: (185, "StringTableMap"), - 0x03909: (185, "WeakHashTableMap"), - 0x03961: (106, "NativeSourceStringMap"), - 0x039b9: (64, "StringMap"), - 0x03a11: (73, "ConsOneByteStringMap"), - 0x03a69: (65, "ConsStringMap"), - 0x03ac1: (77, "ThinOneByteStringMap"), - 0x03b19: (69, "ThinStringMap"), - 0x03b71: (67, "SlicedStringMap"), - 0x03bc9: (75, "SlicedOneByteStringMap"), - 0x03c21: (66, "ExternalStringMap"), - 0x03c79: (82, "ExternalStringWithOneByteDataMap"), - 0x03cd1: (74, "ExternalOneByteStringMap"), - 0x03d29: (98, "ShortExternalStringMap"), - 0x03d81: (114, "ShortExternalStringWithOneByteDataMap"), - 0x03dd9: (0, "InternalizedStringMap"), - 0x03e31: (2, "ExternalInternalizedStringMap"), - 0x03e89: (18, "ExternalInternalizedStringWithOneByteDataMap"), - 0x03ee1: (10, "ExternalOneByteInternalizedStringMap"), - 0x03f39: (34, "ShortExternalInternalizedStringMap"), - 0x03f91: (50, "ShortExternalInternalizedStringWithOneByteDataMap"), - 0x03fe9: (42, "ShortExternalOneByteInternalizedStringMap"), - 0x04041: (106, "ShortExternalOneByteStringMap"), - 0x04099: (140, "FixedUint8ArrayMap"), - 0x040f1: (139, "FixedInt8ArrayMap"), - 0x04149: (142, "FixedUint16ArrayMap"), - 0x041a1: (141, "FixedInt16ArrayMap"), - 0x041f9: (144, "FixedUint32ArrayMap"), - 0x04251: (143, "FixedInt32ArrayMap"), - 0x042a9: (145, "FixedFloat32ArrayMap"), - 0x04301: (146, "FixedFloat64ArrayMap"), - 0x04359: (147, "FixedUint8ClampedArrayMap"), - 0x043b1: (149, "FixedBigUint64ArrayMap"), - 0x04409: (148, "FixedBigInt64ArrayMap"), - 0x04461: (172, "Tuple2Map"), - 0x044b9: (170, "ScriptMap"), - 0x04511: (163, "InterceptorInfoMap"), - 0x04569: (154, "AccessorInfoMap"), - 0x045c1: (153, "AccessCheckInfoMap"), - 0x04619: (155, "AccessorPairMap"), - 0x04671: (156, "AliasedArgumentsEntryMap"), - 0x046c9: (157, "AllocationMementoMap"), - 0x04721: (158, "AllocationSiteMap"), - 0x04779: (159, "AsyncGeneratorRequestMap"), - 0x047d1: (160, "ContextExtensionMap"), - 0x04829: (161, "DebugInfoMap"), - 0x04881: (162, "FunctionTemplateInfoMap"), - 0x048d9: (164, "ModuleInfoEntryMap"), - 0x04931: (165, "ModuleMap"), - 0x04989: (166, "ObjectTemplateInfoMap"), - 0x049e1: (167, "PromiseCapabilityMap"), - 0x04a39: (168, "PromiseReactionMap"), - 0x04a91: (169, "PrototypeInfoMap"), - 0x04ae9: (171, "StackFrameInfoMap"), - 0x04b41: (173, "Tuple3Map"), - 0x04b99: (174, "WasmCompiledModuleMap"), - 0x04bf1: (175, "WasmDebugInfoMap"), - 0x04c49: (176, "WasmSharedModuleDataMap"), - 0x04ca1: (177, "CallableTaskMap"), - 0x04cf9: (178, "CallbackTaskMap"), - 0x04d51: (179, "PromiseFulfillReactionJobTaskMap"), - 0x04da9: (180, "PromiseRejectReactionJobTaskMap"), - 0x04e01: (181, "PromiseResolveThenableJobTaskMap"), + 0x03909: (200, "WeakFixedArrayMap"), + 0x03961: (185, "WeakHashTableMap"), + 0x039b9: (106, "NativeSourceStringMap"), + 0x03a11: (64, "StringMap"), + 0x03a69: (73, "ConsOneByteStringMap"), + 0x03ac1: (65, "ConsStringMap"), + 0x03b19: (77, "ThinOneByteStringMap"), + 0x03b71: (69, "ThinStringMap"), + 0x03bc9: (67, "SlicedStringMap"), + 0x03c21: (75, "SlicedOneByteStringMap"), + 0x03c79: (66, "ExternalStringMap"), + 0x03cd1: (82, "ExternalStringWithOneByteDataMap"), + 0x03d29: (74, "ExternalOneByteStringMap"), + 0x03d81: (98, "ShortExternalStringMap"), + 0x03dd9: (114, "ShortExternalStringWithOneByteDataMap"), + 0x03e31: (0, "InternalizedStringMap"), + 0x03e89: (2, "ExternalInternalizedStringMap"), + 0x03ee1: (18, "ExternalInternalizedStringWithOneByteDataMap"), + 0x03f39: (10, "ExternalOneByteInternalizedStringMap"), + 0x03f91: (34, "ShortExternalInternalizedStringMap"), + 0x03fe9: (50, "ShortExternalInternalizedStringWithOneByteDataMap"), + 0x04041: (42, "ShortExternalOneByteInternalizedStringMap"), + 0x04099: (106, "ShortExternalOneByteStringMap"), + 0x040f1: (140, "FixedUint8ArrayMap"), + 0x04149: (139, "FixedInt8ArrayMap"), + 0x041a1: (142, "FixedUint16ArrayMap"), + 0x041f9: (141, "FixedInt16ArrayMap"), + 0x04251: (144, "FixedUint32ArrayMap"), + 0x042a9: (143, "FixedInt32ArrayMap"), + 0x04301: (145, "FixedFloat32ArrayMap"), + 0x04359: (146, "FixedFloat64ArrayMap"), + 0x043b1: (147, "FixedUint8ClampedArrayMap"), + 0x04409: (149, "FixedBigUint64ArrayMap"), + 0x04461: (148, "FixedBigInt64ArrayMap"), + 0x044b9: (172, "Tuple2Map"), + 0x04511: (170, "ScriptMap"), + 0x04569: (163, "InterceptorInfoMap"), + 0x045c1: (154, "AccessorInfoMap"), + 0x04619: (153, "AccessCheckInfoMap"), + 0x04671: (155, "AccessorPairMap"), + 0x046c9: (156, "AliasedArgumentsEntryMap"), + 0x04721: (157, "AllocationMementoMap"), + 0x04779: (158, "AllocationSiteMap"), + 0x047d1: (159, "AsyncGeneratorRequestMap"), + 0x04829: (160, "ContextExtensionMap"), + 0x04881: (161, "DebugInfoMap"), + 0x048d9: (162, "FunctionTemplateInfoMap"), + 0x04931: (164, "ModuleInfoEntryMap"), + 0x04989: (165, "ModuleMap"), + 0x049e1: (166, "ObjectTemplateInfoMap"), + 0x04a39: (167, "PromiseCapabilityMap"), + 0x04a91: (168, "PromiseReactionMap"), + 0x04ae9: (169, "PrototypeInfoMap"), + 0x04b41: (171, "StackFrameInfoMap"), + 0x04b99: (173, "Tuple3Map"), + 0x04bf1: (174, "WasmCompiledModuleMap"), + 0x04c49: (175, "WasmDebugInfoMap"), + 0x04ca1: (176, "WasmSharedModuleDataMap"), + 0x04cf9: (177, "CallableTaskMap"), + 0x04d51: (178, "CallbackTaskMap"), + 0x04da9: (179, "PromiseFulfillReactionJobTaskMap"), + 0x04e01: (180, "PromiseRejectReactionJobTaskMap"), + 0x04e59: (181, "PromiseResolveThenableJobTaskMap"), } # List of known V8 objects. @@ -312,15 +314,15 @@ KNOWN_OBJECTS = { ("OLD_SPACE", 0x02909): "EmptyOrderedHashSet", ("OLD_SPACE", 0x02941): "EmptyPropertyCell", ("OLD_SPACE", 0x02969): "EmptyWeakCell", - ("OLD_SPACE", 0x029d9): "NoElementsProtector", - ("OLD_SPACE", 0x02a01): "IsConcatSpreadableProtector", - ("OLD_SPACE", 0x02a11): "SpeciesProtector", - ("OLD_SPACE", 0x02a39): "StringLengthProtector", - ("OLD_SPACE", 0x02a49): "ArrayIteratorProtector", - ("OLD_SPACE", 0x02a71): "ArrayBufferNeuteringProtector", - ("OLD_SPACE", 0x02af9): "InfinityValue", - ("OLD_SPACE", 0x02b09): "MinusZeroValue", - ("OLD_SPACE", 0x02b19): "MinusInfinityValue", + ("OLD_SPACE", 0x029e9): "NoElementsProtector", + ("OLD_SPACE", 0x02a11): "IsConcatSpreadableProtector", + ("OLD_SPACE", 0x02a21): "SpeciesProtector", + ("OLD_SPACE", 0x02a49): "StringLengthProtector", + ("OLD_SPACE", 0x02a59): "ArrayIteratorProtector", + ("OLD_SPACE", 0x02a81): "ArrayBufferNeuteringProtector", + ("OLD_SPACE", 0x02b09): "InfinityValue", + ("OLD_SPACE", 0x02b19): "MinusZeroValue", + ("OLD_SPACE", 0x02b29): "MinusInfinityValue", } # List of known V8 Frame Markers.