[heap] Introduce LocalHandleScope for background threads
Add LocalHandleScope to allow for local handles in LocalHeaps (background threads). This class is similar to HandleScope which still needs to be used on the main thread. When performing a GC, the main thread halts all background threads at a safepoint such that it can safely iterate their roots. Bug: v8:10315 Change-Id: Id8f5d54cc2535e004081ccdef15dc03a39b2d0f0 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2111218 Commit-Queue: Dominik Inführ <dinfuehr@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#66853}
This commit is contained in:
parent
04774ffaaa
commit
12597a8ae9
3
BUILD.gn
3
BUILD.gn
@ -2325,6 +2325,9 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/handles/handles-inl.h",
|
||||
"src/handles/handles.cc",
|
||||
"src/handles/handles.h",
|
||||
"src/handles/local-handles-inl.h",
|
||||
"src/handles/local-handles.cc",
|
||||
"src/handles/local-handles.h",
|
||||
"src/handles/maybe-handles-inl.h",
|
||||
"src/handles/maybe-handles.h",
|
||||
"src/heap/array-buffer-collector.cc",
|
||||
|
1
src/DEPS
1
src/DEPS
@ -16,6 +16,7 @@ include_rules = [
|
||||
"+src/heap/heap-inl.h",
|
||||
"+src/heap/heap-write-barrier-inl.h",
|
||||
"+src/heap/heap-write-barrier.h",
|
||||
"+src/heap/local-heap.h",
|
||||
"+src/heap/off-thread-factory-inl.h",
|
||||
"+src/heap/off-thread-factory.h",
|
||||
"+src/heap/read-only-heap-inl.h",
|
||||
|
@ -909,6 +909,7 @@ DEFINE_BOOL_READONLY(array_buffer_extension, V8_ARRAY_BUFFER_EXTENSION_BOOL,
|
||||
DEFINE_IMPLICATION(array_buffer_extension, always_promote_young_mc)
|
||||
DEFINE_BOOL(concurrent_array_buffer_sweeping, true,
|
||||
"concurrently sweep array buffers")
|
||||
DEFINE_BOOL(local_heaps, false, "allow heap access from background tasks")
|
||||
DEFINE_BOOL(parallel_marking, true, "use parallel marking in atomic pause")
|
||||
DEFINE_INT(ephemeron_fixpoint_iterations, 10,
|
||||
"number of fixpoint iterations it takes to switch to linear "
|
||||
|
@ -8,17 +8,23 @@
|
||||
#include "src/execution/isolate.h"
|
||||
#include "src/execution/off-thread-isolate.h"
|
||||
#include "src/handles/handles.h"
|
||||
#include "src/handles/local-handles-inl.h"
|
||||
#include "src/sanitizer/msan.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class LocalHeap;
|
||||
|
||||
HandleBase::HandleBase(Address object, Isolate* isolate)
|
||||
: location_(HandleScope::GetHandle(isolate, object)) {}
|
||||
|
||||
HandleBase::HandleBase(Address object, OffThreadIsolate* isolate)
|
||||
: location_(isolate->NewHandle(object)) {}
|
||||
|
||||
HandleBase::HandleBase(Address object, LocalHeap* local_heap)
|
||||
: location_(LocalHandleScope::GetHandle(local_heap, object)) {}
|
||||
|
||||
// Allocate a new handle for the object, do not canonicalize.
|
||||
|
||||
template <typename T>
|
||||
@ -41,6 +47,10 @@ template <typename T>
|
||||
Handle<T>::Handle(T object, OffThreadIsolate* isolate)
|
||||
: HandleBase(object.ptr(), isolate) {}
|
||||
|
||||
template <typename T>
|
||||
Handle<T>::Handle(T object, LocalHeap* local_heap)
|
||||
: HandleBase(object.ptr(), local_heap) {}
|
||||
|
||||
template <typename T>
|
||||
V8_INLINE Handle<T> handle(T object, Isolate* isolate) {
|
||||
return Handle<T>(object, isolate);
|
||||
@ -51,6 +61,11 @@ V8_INLINE Handle<T> handle(T object, OffThreadIsolate* isolate) {
|
||||
return Handle<T>(object, isolate);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
V8_INLINE Handle<T> handle(T object, LocalHeap* local_heap) {
|
||||
return Handle<T>(object, local_heap);
|
||||
}
|
||||
|
||||
// Convenience overloads for when we already have a Handle, but want
|
||||
// either a Handle or an Handle.
|
||||
template <typename T>
|
||||
@ -61,6 +76,10 @@ template <typename T>
|
||||
V8_INLINE Handle<T> handle(Handle<T> handle, OffThreadIsolate* isolate) {
|
||||
return Handle<T>(*handle);
|
||||
}
|
||||
template <typename T>
|
||||
V8_INLINE Handle<T> handle(Handle<T> handle, LocalHeap* local_heap) {
|
||||
return Handle<T>(*handle, local_heap);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::ostream& operator<<(std::ostream& os, Handle<T> handle) {
|
||||
|
@ -21,6 +21,7 @@ namespace internal {
|
||||
class DeferredHandles;
|
||||
class HandleScopeImplementer;
|
||||
class Isolate;
|
||||
class LocalHeap;
|
||||
class OffThreadIsolate;
|
||||
template <typename T>
|
||||
class MaybeHandle;
|
||||
@ -28,6 +29,7 @@ class Object;
|
||||
class OrderedHashMap;
|
||||
class OrderedHashSet;
|
||||
class OrderedNameDictionary;
|
||||
class RootVisitor;
|
||||
class SmallOrderedHashMap;
|
||||
class SmallOrderedHashSet;
|
||||
class SmallOrderedNameDictionary;
|
||||
@ -40,6 +42,7 @@ class HandleBase {
|
||||
V8_INLINE explicit HandleBase(Address* location) : location_(location) {}
|
||||
V8_INLINE explicit HandleBase(Address object, Isolate* isolate);
|
||||
V8_INLINE explicit HandleBase(Address object, OffThreadIsolate* isolate);
|
||||
V8_INLINE explicit HandleBase(Address object, LocalHeap* local_heap);
|
||||
|
||||
// Check if this handle refers to the exact same object as the other handle.
|
||||
V8_INLINE bool is_identical_to(const HandleBase that) const {
|
||||
@ -121,6 +124,7 @@ class Handle final : public HandleBase {
|
||||
|
||||
V8_INLINE Handle(T object, Isolate* isolate);
|
||||
V8_INLINE Handle(T object, OffThreadIsolate* isolate);
|
||||
V8_INLINE Handle(T object, LocalHeap* local_heap);
|
||||
|
||||
// Allocate a new handle for the object, do not canonicalize.
|
||||
V8_INLINE static Handle<T> New(T object, Isolate* isolate);
|
||||
|
61
src/handles/local-handles-inl.h
Normal file
61
src/handles/local-handles-inl.h
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright 2020 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_HANDLES_LOCAL_HANDLES_INL_H_
|
||||
#define V8_HANDLES_LOCAL_HANDLES_INL_H_
|
||||
|
||||
#include "src/handles/local-handles.h"
|
||||
|
||||
#include "src/sanitizer/msan.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// static
|
||||
V8_INLINE Address* LocalHandleScope::GetHandle(LocalHeap* local_heap,
|
||||
Address value) {
|
||||
LocalHandles* handles = local_heap->handles();
|
||||
Address* result = handles->scope_.next;
|
||||
if (result == handles->scope_.limit) {
|
||||
result = handles->AddBlock();
|
||||
}
|
||||
DCHECK_LT(result, handles->scope_.limit);
|
||||
handles->scope_.next++;
|
||||
*result = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
LocalHandleScope::LocalHandleScope(LocalHeap* local_heap) {
|
||||
LocalHandles* handles = local_heap->handles();
|
||||
local_heap_ = local_heap;
|
||||
prev_next_ = handles->scope_.next;
|
||||
prev_limit_ = handles->scope_.limit;
|
||||
handles->scope_.level++;
|
||||
}
|
||||
|
||||
LocalHandleScope::~LocalHandleScope() {
|
||||
LocalHandles* handles = local_heap_->handles();
|
||||
Address* old_limit = handles->scope_.limit;
|
||||
|
||||
handles->scope_.next = prev_next_;
|
||||
handles->scope_.limit = prev_limit_;
|
||||
handles->scope_.level--;
|
||||
|
||||
if (old_limit != handles->scope_.limit) {
|
||||
handles->RemoveBlocks();
|
||||
old_limit = handles->scope_.limit;
|
||||
}
|
||||
|
||||
// TODO(dinfuehr): Zap handles
|
||||
|
||||
MSAN_ALLOCATED_UNINITIALIZED_MEMORY(
|
||||
handles->scope_.next,
|
||||
static_cast<size_t>(reinterpret_cast<Address>(old_limit) -
|
||||
reinterpret_cast<Address>(handles->scope_.next)));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_HANDLES_LOCAL_HANDLES_INL_H_
|
58
src/handles/local-handles.cc
Normal file
58
src/handles/local-handles.cc
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2012 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 "src/handles/local-handles.h"
|
||||
|
||||
#include "src/api/api.h"
|
||||
#include "src/handles/handles.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
LocalHandles::LocalHandles() { scope_.Initialize(); }
|
||||
|
||||
void LocalHandles::Iterate(RootVisitor* visitor) {
|
||||
for (int i = 0; i < static_cast<int>(blocks_.size()) - 1; i++) {
|
||||
Address* block = blocks_[i];
|
||||
visitor->VisitRootPointers(Root::kHandleScope, nullptr,
|
||||
FullObjectSlot(block),
|
||||
FullObjectSlot(&block[kHandleBlockSize]));
|
||||
}
|
||||
|
||||
if (!blocks_.empty()) {
|
||||
Address* block = blocks_.back();
|
||||
visitor->VisitRootPointers(Root::kHandleScope, nullptr,
|
||||
FullObjectSlot(block),
|
||||
FullObjectSlot(scope_.next));
|
||||
}
|
||||
}
|
||||
|
||||
Address* LocalHandles::AddBlock() {
|
||||
DCHECK_EQ(scope_.next, scope_.limit);
|
||||
Address* block = NewArray<Address>(kHandleBlockSize);
|
||||
blocks_.push_back(block);
|
||||
scope_.next = block;
|
||||
scope_.limit = block + kHandleBlockSize;
|
||||
return block;
|
||||
}
|
||||
|
||||
void LocalHandles::RemoveBlocks() {
|
||||
while (!blocks_.empty()) {
|
||||
Address* block_start = blocks_.back();
|
||||
Address* block_limit = block_start + kHandleBlockSize;
|
||||
|
||||
if (block_limit == scope_.limit) {
|
||||
break;
|
||||
}
|
||||
|
||||
blocks_.pop_back();
|
||||
|
||||
// TODO(dinfuehr): Zap handles in block
|
||||
|
||||
DeleteArray(block_start);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
57
src/handles/local-handles.h
Normal file
57
src/handles/local-handles.h
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2011 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_HANDLES_LOCAL_HANDLES_H_
|
||||
#define V8_HANDLES_LOCAL_HANDLES_H_
|
||||
|
||||
#include "include/v8-internal.h"
|
||||
#include "src/base/functional.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/handles/handles.h"
|
||||
#include "src/heap/local-heap.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class RootVisitor;
|
||||
|
||||
class LocalHandles {
|
||||
public:
|
||||
LocalHandles();
|
||||
|
||||
void Iterate(RootVisitor* visitor);
|
||||
|
||||
private:
|
||||
HandleScopeData scope_;
|
||||
std::vector<Address*> blocks_;
|
||||
|
||||
V8_EXPORT_PRIVATE Address* AddBlock();
|
||||
V8_EXPORT_PRIVATE void RemoveBlocks();
|
||||
|
||||
friend class LocalHandleScope;
|
||||
};
|
||||
|
||||
class LocalHandleScope {
|
||||
public:
|
||||
explicit inline LocalHandleScope(LocalHeap* local_heap);
|
||||
inline ~LocalHandleScope();
|
||||
|
||||
V8_INLINE static Address* GetHandle(LocalHeap* local_heap, Address value);
|
||||
|
||||
private:
|
||||
// Prevent heap allocation or illegal handle scopes.
|
||||
void* operator new(size_t size);
|
||||
void operator delete(void* size_t);
|
||||
|
||||
LocalHeap* local_heap_;
|
||||
Address* prev_limit_;
|
||||
Address* prev_next_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LocalHandleScope);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_HANDLES_LOCAL_HANDLES_H_
|
@ -822,12 +822,6 @@ void Heap::GarbageCollectionPrologue() {
|
||||
{
|
||||
AllowHeapAllocation for_the_first_part_of_prologue;
|
||||
gc_count_++;
|
||||
|
||||
#ifdef VERIFY_HEAP
|
||||
if (FLAG_verify_heap) {
|
||||
Verify();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reset GC statistics.
|
||||
@ -1121,12 +1115,6 @@ void Heap::GarbageCollectionEpilogue() {
|
||||
ZapFromSpace();
|
||||
}
|
||||
|
||||
#ifdef VERIFY_HEAP
|
||||
if (FLAG_verify_heap) {
|
||||
Verify();
|
||||
}
|
||||
#endif
|
||||
|
||||
AllowHeapAllocation for_the_rest_of_the_epilogue;
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -2022,6 +2010,13 @@ bool Heap::PerformGarbageCollection(
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_local_heaps) safepoint()->Start();
|
||||
#ifdef VERIFY_HEAP
|
||||
if (FLAG_verify_heap) {
|
||||
Verify();
|
||||
}
|
||||
#endif
|
||||
|
||||
EnsureFromSpaceIsCommitted();
|
||||
|
||||
size_t start_young_generation_size =
|
||||
@ -2095,6 +2090,13 @@ bool Heap::PerformGarbageCollection(
|
||||
local_embedder_heap_tracer()->TraceEpilogue();
|
||||
}
|
||||
|
||||
#ifdef VERIFY_HEAP
|
||||
if (FLAG_verify_heap) {
|
||||
Verify();
|
||||
}
|
||||
#endif
|
||||
if (FLAG_local_heaps) safepoint()->End();
|
||||
|
||||
{
|
||||
TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_WEAK_GLOBAL_HANDLES);
|
||||
gc_post_processing_depth_++;
|
||||
@ -4467,6 +4469,12 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
|
||||
FixStaleLeftTrimmedHandlesVisitor left_trim_visitor(this);
|
||||
isolate_->handle_scope_implementer()->Iterate(&left_trim_visitor);
|
||||
isolate_->handle_scope_implementer()->Iterate(v);
|
||||
|
||||
if (FLAG_local_heaps) {
|
||||
safepoint_->Iterate(&left_trim_visitor);
|
||||
safepoint_->Iterate(v);
|
||||
}
|
||||
|
||||
isolate_->IterateDeferredHandles(&left_trim_visitor);
|
||||
isolate_->IterateDeferredHandles(v);
|
||||
v->Synchronize(VisitorSynchronization::kHandleScope);
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/heap/local-heap.h"
|
||||
#include "src/handles/local-handles.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/heap/safepoint.h"
|
||||
|
||||
@ -14,7 +15,8 @@ LocalHeap::LocalHeap(Heap* heap)
|
||||
state_(ThreadState::Running),
|
||||
safepoint_requested_(false),
|
||||
prev_(nullptr),
|
||||
next_(nullptr) {
|
||||
next_(nullptr),
|
||||
handles_(new LocalHandles) {
|
||||
heap_->safepoint()->AddLocalHeap(this);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define V8_HEAP_LOCAL_HEAP_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "src/base/platform/condition-variable.h"
|
||||
#include "src/base/platform/mutex.h"
|
||||
@ -15,6 +16,7 @@ namespace internal {
|
||||
|
||||
class Heap;
|
||||
class Safepoint;
|
||||
class LocalHandles;
|
||||
|
||||
class LocalHeap {
|
||||
public:
|
||||
@ -29,6 +31,8 @@ class LocalHeap {
|
||||
// from the main thread.
|
||||
V8_EXPORT_PRIVATE void Safepoint();
|
||||
|
||||
LocalHandles* handles() { return handles_.get(); }
|
||||
|
||||
private:
|
||||
enum class ThreadState {
|
||||
// Threads in this state need to be stopped in a safepoint.
|
||||
@ -60,6 +64,8 @@ class LocalHeap {
|
||||
LocalHeap* prev_;
|
||||
LocalHeap* next_;
|
||||
|
||||
std::unique_ptr<LocalHandles> handles_;
|
||||
|
||||
friend class Heap;
|
||||
friend class Safepoint;
|
||||
friend class ParkedScope;
|
||||
|
@ -3,6 +3,8 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/heap/safepoint.h"
|
||||
|
||||
#include "src/handles/local-handles.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/heap/local-heap.h"
|
||||
|
||||
@ -11,6 +13,10 @@ namespace internal {
|
||||
|
||||
Safepoint::Safepoint(Heap* heap) : heap_(heap), local_heaps_head_(nullptr) {}
|
||||
|
||||
void Safepoint::Start() { StopThreads(); }
|
||||
|
||||
void Safepoint::End() { ResumeThreads(); }
|
||||
|
||||
void Safepoint::StopThreads() {
|
||||
local_heaps_mutex_.Lock();
|
||||
|
||||
@ -117,5 +123,12 @@ bool Safepoint::ContainsAnyLocalHeap() {
|
||||
return local_heaps_head_ != nullptr;
|
||||
}
|
||||
|
||||
void Safepoint::Iterate(RootVisitor* visitor) {
|
||||
for (LocalHeap* current = local_heaps_head_; current;
|
||||
current = current->next_) {
|
||||
current->handles()->Iterate(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -13,6 +13,7 @@ namespace internal {
|
||||
|
||||
class Heap;
|
||||
class LocalHeap;
|
||||
class RootVisitor;
|
||||
|
||||
class Safepoint {
|
||||
public:
|
||||
@ -24,6 +25,13 @@ class Safepoint {
|
||||
V8_EXPORT_PRIVATE bool ContainsLocalHeap(LocalHeap* local_heap);
|
||||
V8_EXPORT_PRIVATE bool ContainsAnyLocalHeap();
|
||||
|
||||
// Iterate handles in local heaps
|
||||
void Iterate(RootVisitor* visitor);
|
||||
|
||||
// Use these methods now instead of the more intrusive SafepointScope
|
||||
void Start();
|
||||
void End();
|
||||
|
||||
private:
|
||||
class Barrier {
|
||||
base::Mutex mutex_;
|
||||
|
@ -219,6 +219,7 @@ v8_source_set("cctest_sources") {
|
||||
"test-intl.cc",
|
||||
"test-js-weak-refs.cc",
|
||||
"test-liveedit.cc",
|
||||
"test-local-handles.cc",
|
||||
"test-lockers.cc",
|
||||
"test-log.cc",
|
||||
"test-managed.cc",
|
||||
|
96
test/cctest/test-local-handles.cc
Normal file
96
test/cctest/test-local-handles.cc
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright 2020 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 <memory>
|
||||
|
||||
#include "src/api/api.h"
|
||||
#include "src/base/platform/condition-variable.h"
|
||||
#include "src/base/platform/mutex.h"
|
||||
#include "src/base/platform/semaphore.h"
|
||||
#include "src/handles/handles-inl.h"
|
||||
#include "src/handles/local-handles-inl.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/heap/local-heap.h"
|
||||
#include "src/heap/safepoint.h"
|
||||
#include "src/objects/heap-number.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/heap/heap-utils.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class LocalHandlesThread final : public v8::base::Thread {
|
||||
public:
|
||||
LocalHandlesThread(Heap* heap, Address object, base::Semaphore* sema_started,
|
||||
base::Semaphore* sema_gc_finished)
|
||||
: v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")),
|
||||
heap_(heap),
|
||||
object_(object),
|
||||
sema_started_(sema_started),
|
||||
sema_gc_finished_(sema_gc_finished) {}
|
||||
|
||||
void Run() override {
|
||||
LocalHeap local_heap(heap_);
|
||||
LocalHandleScope scope(&local_heap);
|
||||
|
||||
static constexpr int kNumHandles =
|
||||
kHandleBlockSize * 2 + kHandleBlockSize / 2;
|
||||
|
||||
std::vector<Handle<HeapNumber>> handles;
|
||||
handles.reserve(kNumHandles);
|
||||
|
||||
for (int i = 0; i < kNumHandles; i++) {
|
||||
Handle<HeapNumber> number = handle(
|
||||
HeapNumber::cast(HeapObject::FromAddress(object_)), &local_heap);
|
||||
handles.push_back(number);
|
||||
}
|
||||
|
||||
sema_started_->Signal();
|
||||
|
||||
{
|
||||
ParkedScope scope(&local_heap);
|
||||
sema_gc_finished_->Wait();
|
||||
}
|
||||
|
||||
for (Handle<HeapNumber> handle : handles) {
|
||||
CHECK_EQ(42.0, handle->value());
|
||||
}
|
||||
}
|
||||
|
||||
Heap* heap_;
|
||||
Address object_;
|
||||
base::Semaphore* sema_started_;
|
||||
base::Semaphore* sema_gc_finished_;
|
||||
};
|
||||
|
||||
TEST(CreateLocalHandles) {
|
||||
CcTest::InitializeVM();
|
||||
FLAG_local_heaps = true;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Address object = kNullAddress;
|
||||
|
||||
{
|
||||
HandleScope handle_scope(isolate);
|
||||
Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(42.0);
|
||||
object = (*number).address();
|
||||
}
|
||||
|
||||
base::Semaphore sema_started(0);
|
||||
base::Semaphore sema_gc_finished(0);
|
||||
|
||||
std::unique_ptr<LocalHandlesThread> thread(new LocalHandlesThread(
|
||||
isolate->heap(), object, &sema_started, &sema_gc_finished));
|
||||
CHECK(thread->Start());
|
||||
|
||||
sema_started.Wait();
|
||||
|
||||
CcTest::CollectAllGarbage();
|
||||
sema_gc_finished.Signal();
|
||||
|
||||
thread->Join();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -13,9 +13,9 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
using SafepoinTest = TestWithIsolate;
|
||||
using SafepointTest = TestWithIsolate;
|
||||
|
||||
TEST_F(SafepoinTest, ReachSafepointWithoutLocalHeaps) {
|
||||
TEST_F(SafepointTest, ReachSafepointWithoutLocalHeaps) {
|
||||
Heap* heap = i_isolate()->heap();
|
||||
bool run = false;
|
||||
{
|
||||
@ -45,7 +45,7 @@ class ParkedThread final : public v8::base::Thread {
|
||||
base::Mutex* mutex_;
|
||||
};
|
||||
|
||||
TEST_F(SafepoinTest, StopParkedThreads) {
|
||||
TEST_F(SafepointTest, StopParkedThreads) {
|
||||
Heap* heap = i_isolate()->heap();
|
||||
|
||||
int safepoints = 0;
|
||||
@ -103,7 +103,7 @@ class RunningThread final : public v8::base::Thread {
|
||||
std::atomic<int>* counter_;
|
||||
};
|
||||
|
||||
TEST_F(SafepoinTest, StopRunningThreads) {
|
||||
TEST_F(SafepointTest, StopRunningThreads) {
|
||||
Heap* heap = i_isolate()->heap();
|
||||
|
||||
const int kThreads = 10;
|
||||
|
Loading…
Reference in New Issue
Block a user