// Copyright 2023 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. #include #include #include #include "src/heap/heap.h" #include "test/unittests/heap/heap-utils.h" #include "test/unittests/test-utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace v8 { namespace internal { using StrongRootAllocatorTest = TestWithHeapInternals; TEST_F(StrongRootAllocatorTest, AddressRetained) { ManualGCScope manual_gc_scope(i_isolate()); Global weak; StrongRootAllocator
allocator(heap()); Address* allocated = allocator.allocate(10); { v8::HandleScope scope(v8_isolate()); Handle h = factory()->NewFixedArray(10, AllocationType::kOld); allocated[7] = h->ptr(); Local l = Utils::FixedArrayToLocal(h); weak.Reset(v8_isolate(), l); weak.SetWeak(); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_FALSE(weak.IsEmpty()); allocator.deallocate(allocated, 10); { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_TRUE(weak.IsEmpty()); } TEST_F(StrongRootAllocatorTest, StructNotRetained) { ManualGCScope manual_gc_scope(i_isolate()); Global weak; struct Wrapped { Address content; }; StrongRootAllocator allocator(heap()); Wrapped* allocated = allocator.allocate(10); { v8::HandleScope scope(v8_isolate()); Handle h = factory()->NewFixedArray(10, AllocationType::kOld); allocated[7].content = h->ptr(); Local l = Utils::FixedArrayToLocal(h); weak.Reset(v8_isolate(), l); weak.SetWeak(); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_TRUE(weak.IsEmpty()); allocator.deallocate(allocated, 10); } TEST_F(StrongRootAllocatorTest, VectorRetained) { ManualGCScope manual_gc_scope(i_isolate()); Global weak; { StrongRootAllocator
allocator(heap()); std::vector> v(10, allocator); { v8::HandleScope scope(v8_isolate()); Handle h = factory()->NewFixedArray(10, AllocationType::kOld); v[7] = h->ptr(); Local l = Utils::FixedArrayToLocal(h); weak.Reset(v8_isolate(), l); weak.SetWeak(); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_FALSE(weak.IsEmpty()); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_TRUE(weak.IsEmpty()); } TEST_F(StrongRootAllocatorTest, VectorOfStructNotRetained) { ManualGCScope manual_gc_scope(i_isolate()); Global weak; struct Wrapped { Address content; }; StrongRootAllocator allocator(heap()); std::vector> v(10, allocator); { v8::HandleScope scope(v8_isolate()); Handle h = factory()->NewFixedArray(10, AllocationType::kOld); v[7].content = h->ptr(); Local l = Utils::FixedArrayToLocal(h); weak.Reset(v8_isolate(), l); weak.SetWeak(); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_TRUE(weak.IsEmpty()); } TEST_F(StrongRootAllocatorTest, ListNotRetained) { ManualGCScope manual_gc_scope(i_isolate()); Global weak; StrongRootAllocator
allocator(heap()); std::list> l(allocator); { v8::HandleScope scope(v8_isolate()); Handle h = factory()->NewFixedArray(10, AllocationType::kOld); l.push_back(h->ptr()); Local l = Utils::FixedArrayToLocal(h); weak.Reset(v8_isolate(), l); weak.SetWeak(); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_TRUE(weak.IsEmpty()); } TEST_F(StrongRootAllocatorTest, SetNotRetained) { ManualGCScope manual_gc_scope(i_isolate()); Global weak; StrongRootAllocator
allocator(heap()); std::set, StrongRootAllocator
> s( allocator); { v8::HandleScope scope(v8_isolate()); Handle h = factory()->NewFixedArray(10, AllocationType::kOld); s.insert(h->ptr()); Local l = Utils::FixedArrayToLocal(h); weak.Reset(v8_isolate(), l); weak.SetWeak(); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_TRUE(weak.IsEmpty()); } TEST_F(StrongRootAllocatorTest, LocalVector) { ManualGCScope manual_gc_scope(i_isolate()); Global weak; { v8::HandleScope outer_scope(v8_isolate()); // LocalVector uses the StrongRootAllocator for its backing store. LocalVector v(v8_isolate(), 10); { v8::EscapableHandleScope inner_scope(v8_isolate()); Handle h = factory()->NewFixedArray(10, AllocationType::kOld); Local l = Utils::FixedArrayToLocal(h); weak.Reset(v8_isolate(), l); weak.SetWeak(); v[7] = inner_scope.Escape(l); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_FALSE(weak.IsEmpty()); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_TRUE(weak.IsEmpty()); } #ifdef V8_ENABLE_DIRECT_LOCAL TEST_F(StrongRootAllocatorTest, LocalVectorWithDirect) { ManualGCScope manual_gc_scope(i_isolate()); Global weak; { // LocalVector uses the StrongRootAllocator for its backing store. LocalVector v(v8_isolate(), 10); { v8::HandleScope scope(v8_isolate()); Handle h = factory()->NewFixedArray(10, AllocationType::kOld); Local l = Utils::FixedArrayToLocal(h); // This is legal without escaping, because locals are direct. v[7] = l; weak.Reset(v8_isolate(), l); weak.SetWeak(); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_FALSE(weak.IsEmpty()); } { DisableConservativeStackScanningScopeForTesting no_stack_scanning(heap()); InvokeMajorGC(); } EXPECT_TRUE(weak.IsEmpty()); } #endif // V8_ENABLE_DIRECT_LOCAL } // namespace internal } // namespace v8