[heap] Add PersistentHandles container
Adds the PersistentHandles class, which serves as a container for handles that can be passed back and forth between threads. Allocation and deallocation of this class is thread-safe and the isolate tracks all PersistentHandles containers. Design doc: https://docs.google.com/document/d/17yKs-6apE2rGEag7tDsoyeRxg99c1dXyXQ2MfHe65tY/edit?usp=sharing Bug: v8:10315 Change-Id: I4b9c958c9a57d755ca68862197501f75274670fb Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2128058 Commit-Queue: Dominik Inführ <dinfuehr@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#67004}
This commit is contained in:
parent
dd1dbd99a6
commit
744a1d23b2
2
BUILD.gn
2
BUILD.gn
@ -2339,6 +2339,8 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/handles/local-handles.h",
|
||||
"src/handles/maybe-handles-inl.h",
|
||||
"src/handles/maybe-handles.h",
|
||||
"src/handles/persistent-handles.cc",
|
||||
"src/handles/persistent-handles.h",
|
||||
"src/heap/array-buffer-collector.cc",
|
||||
"src/heap/array-buffer-collector.h",
|
||||
"src/heap/array-buffer-sweeper.cc",
|
||||
|
1
src/DEPS
1
src/DEPS
@ -21,6 +21,7 @@ include_rules = [
|
||||
"+src/heap/off-thread-factory.h",
|
||||
"+src/heap/read-only-heap-inl.h",
|
||||
"+src/heap/read-only-heap.h",
|
||||
"+src/heap/safepoint.h",
|
||||
"-src/inspector",
|
||||
"-src/interpreter",
|
||||
"+src/interpreter/bytecode-array-accessor.h",
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "src/execution/simulator.h"
|
||||
#include "src/execution/v8threads.h"
|
||||
#include "src/execution/vm-state-inl.h"
|
||||
#include "src/handles/persistent-handles.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/heap/read-only-heap.h"
|
||||
#include "src/ic/stub-cache.h"
|
||||
@ -2857,6 +2858,7 @@ Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator)
|
||||
builtins_(this),
|
||||
rail_mode_(PERFORMANCE_ANIMATION),
|
||||
code_event_dispatcher_(new CodeEventDispatcher()),
|
||||
persistent_handles_list_(new PersistentHandlesList(this)),
|
||||
jitless_(FLAG_jitless),
|
||||
#if V8_SFI_HAS_UNIQUE_ID
|
||||
next_unique_sfi_id_(0),
|
||||
@ -3654,6 +3656,10 @@ void Isolate::UnlinkDeferredHandles(DeferredHandles* deferred) {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<PersistentHandles> Isolate::NewPersistentHandles() {
|
||||
return std::make_unique<PersistentHandles>(this);
|
||||
}
|
||||
|
||||
void Isolate::DumpAndResetStats() {
|
||||
if (turbo_statistics() != nullptr) {
|
||||
DCHECK(FLAG_turbo_stats || FLAG_turbo_stats_nvp);
|
||||
|
@ -85,6 +85,8 @@ class MaterializedObjectStore;
|
||||
class Microtask;
|
||||
class MicrotaskQueue;
|
||||
class OptimizingCompileDispatcher;
|
||||
class PersistentHandles;
|
||||
class PersistentHandlesList;
|
||||
class ReadOnlyDeserializer;
|
||||
class RegExpStack;
|
||||
class RootVisitor;
|
||||
@ -1200,6 +1202,12 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
||||
void LinkDeferredHandles(DeferredHandles* deferred_handles);
|
||||
void UnlinkDeferredHandles(DeferredHandles* deferred_handles);
|
||||
|
||||
std::unique_ptr<PersistentHandles> NewPersistentHandles();
|
||||
|
||||
PersistentHandlesList* persistent_handles_list() {
|
||||
return persistent_handles_list_.get();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsDeferredHandle(Address* location);
|
||||
#endif // DEBUG
|
||||
@ -1764,6 +1772,8 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
||||
DeferredHandles* deferred_handles_head_ = nullptr;
|
||||
OptimizingCompileDispatcher* optimizing_compile_dispatcher_ = nullptr;
|
||||
|
||||
std::unique_ptr<PersistentHandlesList> persistent_handles_list_;
|
||||
|
||||
// Counts deopt points if deopt_every_n_times is enabled.
|
||||
unsigned int stress_deopt_count_ = 0;
|
||||
|
||||
|
122
src/handles/persistent-handles.cc
Normal file
122
src/handles/persistent-handles.cc
Normal file
@ -0,0 +1,122 @@
|
||||
// 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 "src/handles/persistent-handles.h"
|
||||
|
||||
#include "src/api/api.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/heap/safepoint.h"
|
||||
#include "src/utils/allocation.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
PersistentHandles::PersistentHandles(Isolate* isolate, size_t block_size)
|
||||
: isolate_(isolate),
|
||||
block_size_(block_size),
|
||||
block_next_(nullptr),
|
||||
block_limit_(nullptr),
|
||||
prev_(nullptr),
|
||||
next_(nullptr) {
|
||||
isolate->persistent_handles_list()->Add(this);
|
||||
}
|
||||
|
||||
PersistentHandles::~PersistentHandles() {
|
||||
isolate_->persistent_handles_list()->Remove(this);
|
||||
|
||||
for (Address* block_start : blocks_) {
|
||||
DeleteArray(block_start);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void PersistentHandles::Attach(LocalHeap* local_heap) {
|
||||
DCHECK_NULL(owner_);
|
||||
owner_ = local_heap;
|
||||
}
|
||||
|
||||
void PersistentHandles::Detach() {
|
||||
DCHECK_NOT_NULL(owner_);
|
||||
owner_ = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void PersistentHandles::AddBlock() {
|
||||
DCHECK_EQ(block_next_, block_limit_);
|
||||
|
||||
Address* block_start = NewArray<Address>(block_size_);
|
||||
blocks_.push_back(block_start);
|
||||
|
||||
block_next_ = block_start;
|
||||
block_limit_ = block_start + block_size_;
|
||||
}
|
||||
|
||||
Handle<Object> PersistentHandles::NewHandle(Address value) {
|
||||
#ifdef DEBUG
|
||||
if (owner_) DCHECK(!owner_->IsParked());
|
||||
#endif
|
||||
return Handle<Object>(GetHandle(value));
|
||||
}
|
||||
|
||||
Address* PersistentHandles::GetHandle(Address value) {
|
||||
if (block_next_ == block_limit_) {
|
||||
AddBlock();
|
||||
}
|
||||
|
||||
DCHECK_LT(block_next_, block_limit_);
|
||||
*block_next_ = value;
|
||||
return block_next_++;
|
||||
}
|
||||
|
||||
void PersistentHandles::Iterate(RootVisitor* visitor) {
|
||||
for (int i = 0; i < static_cast<int>(blocks_.size()) - 1; i++) {
|
||||
Address* block_start = blocks_[i];
|
||||
Address* block_end = block_start + block_size_;
|
||||
visitor->VisitRootPointers(Root::kHandleScope, nullptr,
|
||||
FullObjectSlot(block_start),
|
||||
FullObjectSlot(block_end));
|
||||
}
|
||||
|
||||
if (!blocks_.empty()) {
|
||||
Address* block_start = blocks_.back();
|
||||
visitor->VisitRootPointers(Root::kHandleScope, nullptr,
|
||||
FullObjectSlot(block_start),
|
||||
FullObjectSlot(block_next_));
|
||||
}
|
||||
}
|
||||
|
||||
void PersistentHandlesList::Add(PersistentHandles* persistent_handles) {
|
||||
base::MutexGuard guard(&persistent_handles_mutex_);
|
||||
if (persistent_handles_head_)
|
||||
persistent_handles_head_->prev_ = persistent_handles;
|
||||
persistent_handles->prev_ = nullptr;
|
||||
persistent_handles->next_ = persistent_handles_head_;
|
||||
persistent_handles_head_ = persistent_handles;
|
||||
}
|
||||
|
||||
void PersistentHandlesList::Remove(PersistentHandles* persistent_handles) {
|
||||
base::MutexGuard guard(&persistent_handles_mutex_);
|
||||
if (persistent_handles->next_)
|
||||
persistent_handles->next_->prev_ = persistent_handles->prev_;
|
||||
if (persistent_handles->prev_)
|
||||
persistent_handles->prev_->next_ = persistent_handles->next_;
|
||||
else
|
||||
persistent_handles_head_ = persistent_handles->next_;
|
||||
}
|
||||
|
||||
void PersistentHandlesList::Iterate(RootVisitor* visitor) {
|
||||
#if DEBUG
|
||||
DCHECK(isolate_->heap()->safepoint()->IsActive());
|
||||
#else
|
||||
USE(isolate_);
|
||||
#endif
|
||||
base::MutexGuard guard(&persistent_handles_mutex_);
|
||||
for (PersistentHandles* current = persistent_handles_head_; current;
|
||||
current = current->next_) {
|
||||
current->Iterate(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
85
src/handles/persistent-handles.h
Normal file
85
src/handles/persistent-handles.h
Normal file
@ -0,0 +1,85 @@
|
||||
// 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_PERSISTENT_HANDLES_H_
|
||||
#define V8_HANDLES_PERSISTENT_HANDLES_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "include/v8-internal.h"
|
||||
#include "src/api/api.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/objects/visitors.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class Heap;
|
||||
|
||||
class PersistentHandles {
|
||||
public:
|
||||
V8_EXPORT_PRIVATE explicit PersistentHandles(
|
||||
Isolate* isolate, size_t block_size = kHandleBlockSize);
|
||||
V8_EXPORT_PRIVATE ~PersistentHandles();
|
||||
|
||||
PersistentHandles(const PersistentHandles&) = delete;
|
||||
PersistentHandles& operator=(const PersistentHandles&) = delete;
|
||||
|
||||
void Iterate(RootVisitor* visitor);
|
||||
|
||||
V8_EXPORT_PRIVATE Handle<Object> NewHandle(Address value);
|
||||
|
||||
private:
|
||||
void AddBlock();
|
||||
Address* GetHandle(Address value);
|
||||
|
||||
#ifdef DEBUG
|
||||
void Attach(LocalHeap* local_heap);
|
||||
void Detach();
|
||||
|
||||
LocalHeap* owner_ = nullptr;
|
||||
|
||||
#else
|
||||
void Attach(LocalHeap*) {}
|
||||
void Detach() {}
|
||||
#endif
|
||||
|
||||
Isolate* isolate_;
|
||||
std::vector<Address*> blocks_;
|
||||
size_t block_size_;
|
||||
|
||||
Address* block_next_;
|
||||
Address* block_limit_;
|
||||
|
||||
PersistentHandles* prev_;
|
||||
PersistentHandles* next_;
|
||||
|
||||
friend class PersistentHandlesList;
|
||||
friend class LocalHeap;
|
||||
};
|
||||
|
||||
class PersistentHandlesList {
|
||||
public:
|
||||
explicit PersistentHandlesList(Isolate* isolate)
|
||||
: isolate_(isolate), persistent_handles_head_(nullptr) {}
|
||||
|
||||
// Iteration is only safe during a safepoint
|
||||
void Iterate(RootVisitor* visitor);
|
||||
|
||||
private:
|
||||
void Add(PersistentHandles* persistent_handles);
|
||||
void Remove(PersistentHandles* persistent_handles);
|
||||
|
||||
Isolate* isolate_;
|
||||
|
||||
base::Mutex persistent_handles_mutex_;
|
||||
PersistentHandles* persistent_handles_head_ = nullptr;
|
||||
|
||||
friend class PersistentHandles;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_HANDLES_PERSISTENT_HANDLES_H_
|
@ -4473,6 +4473,8 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
|
||||
if (FLAG_local_heaps) {
|
||||
safepoint_->Iterate(&left_trim_visitor);
|
||||
safepoint_->Iterate(v);
|
||||
isolate_->persistent_handles_list()->Iterate(&left_trim_visitor);
|
||||
isolate_->persistent_handles_list()->Iterate(v);
|
||||
}
|
||||
|
||||
isolate_->IterateDeferredHandles(&left_trim_visitor);
|
||||
@ -5376,7 +5378,12 @@ void Heap::StartTearDown() {
|
||||
// a good time to run heap verification (if requested), before starting to
|
||||
// tear down parts of the Isolate.
|
||||
if (FLAG_verify_heap) {
|
||||
Verify();
|
||||
if (FLAG_local_heaps) {
|
||||
SafepointScope scope(this);
|
||||
Verify();
|
||||
} else {
|
||||
Verify();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "src/heap/object-stats.h"
|
||||
#include "src/heap/objects-visiting-inl.h"
|
||||
#include "src/heap/objects-visiting.h"
|
||||
#include "src/heap/safepoint.h"
|
||||
#include "src/heap/sweeper.h"
|
||||
#include "src/init/v8.h"
|
||||
#include "src/numbers/conversions.h"
|
||||
@ -406,8 +407,10 @@ void IncrementalMarking::MarkRoots() {
|
||||
DCHECK(!finalize_marking_completed_);
|
||||
DCHECK(IsMarking());
|
||||
|
||||
if (FLAG_local_heaps) heap_->safepoint()->Start();
|
||||
IncrementalMarkingRootMarkingVisitor visitor(this);
|
||||
heap_->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG_IGNORE_STACK);
|
||||
if (FLAG_local_heaps) heap_->safepoint()->End();
|
||||
}
|
||||
|
||||
bool IncrementalMarking::ShouldRetainMap(Map map, int age) {
|
||||
|
@ -3,21 +3,30 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/heap/local-heap.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "src/base/platform/mutex.h"
|
||||
#include "src/handles/local-handles.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/heap/safepoint.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
LocalHeap::LocalHeap(Heap* heap)
|
||||
LocalHeap::LocalHeap(Heap* heap,
|
||||
std::unique_ptr<PersistentHandles> persistent_handles)
|
||||
: heap_(heap),
|
||||
state_(ThreadState::Running),
|
||||
safepoint_requested_(false),
|
||||
prev_(nullptr),
|
||||
next_(nullptr),
|
||||
handles_(new LocalHandles) {
|
||||
handles_(new LocalHandles),
|
||||
persistent_handles_(std::move(persistent_handles)) {
|
||||
heap_->safepoint()->AddLocalHeap(this);
|
||||
if (persistent_handles_) {
|
||||
persistent_handles_->Attach(this);
|
||||
}
|
||||
}
|
||||
|
||||
LocalHeap::~LocalHeap() {
|
||||
@ -27,6 +36,24 @@ LocalHeap::~LocalHeap() {
|
||||
heap_->safepoint()->RemoveLocalHeap(this);
|
||||
}
|
||||
|
||||
Handle<Object> LocalHeap::NewPersistentHandle(Address value) {
|
||||
if (!persistent_handles_) {
|
||||
persistent_handles_.reset(
|
||||
heap_->isolate()->NewPersistentHandles().release());
|
||||
}
|
||||
return persistent_handles_->NewHandle(value);
|
||||
}
|
||||
|
||||
std::unique_ptr<PersistentHandles> LocalHeap::DetachPersistentHandles() {
|
||||
if (persistent_handles_) persistent_handles_->Detach();
|
||||
return std::move(persistent_handles_);
|
||||
}
|
||||
|
||||
bool LocalHeap::IsParked() {
|
||||
base::MutexGuard guard(&state_mutex_);
|
||||
return state_ == ThreadState::Parked;
|
||||
}
|
||||
|
||||
void LocalHeap::Park() {
|
||||
base::MutexGuard guard(&state_mutex_);
|
||||
CHECK(state_ == ThreadState::Running);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "src/base/platform/condition-variable.h"
|
||||
#include "src/base/platform/mutex.h"
|
||||
#include "src/execution/isolate.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -17,10 +18,13 @@ namespace internal {
|
||||
class Heap;
|
||||
class Safepoint;
|
||||
class LocalHandles;
|
||||
class PersistentHandles;
|
||||
|
||||
class LocalHeap {
|
||||
public:
|
||||
V8_EXPORT_PRIVATE explicit LocalHeap(Heap* heap);
|
||||
V8_EXPORT_PRIVATE explicit LocalHeap(
|
||||
Heap* heap,
|
||||
std::unique_ptr<PersistentHandles> persistent_handles = nullptr);
|
||||
V8_EXPORT_PRIVATE ~LocalHeap();
|
||||
|
||||
// Invoked by main thread to signal this thread that it needs to halt in a
|
||||
@ -33,6 +37,12 @@ class LocalHeap {
|
||||
|
||||
LocalHandles* handles() { return handles_.get(); }
|
||||
|
||||
V8_EXPORT_PRIVATE Handle<Object> NewPersistentHandle(Address value);
|
||||
V8_EXPORT_PRIVATE std::unique_ptr<PersistentHandles>
|
||||
DetachPersistentHandles();
|
||||
|
||||
bool IsParked();
|
||||
|
||||
private:
|
||||
enum class ThreadState {
|
||||
// Threads in this state need to be stopped in a safepoint.
|
||||
@ -65,6 +75,7 @@ class LocalHeap {
|
||||
LocalHeap* next_;
|
||||
|
||||
std::unique_ptr<LocalHandles> handles_;
|
||||
std::unique_ptr<PersistentHandles> persistent_handles_;
|
||||
|
||||
friend class Heap;
|
||||
friend class Safepoint;
|
||||
|
@ -5,13 +5,15 @@
|
||||
#include "src/heap/safepoint.h"
|
||||
|
||||
#include "src/handles/local-handles.h"
|
||||
#include "src/handles/persistent-handles.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/heap/local-heap.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
Safepoint::Safepoint(Heap* heap) : heap_(heap), local_heaps_head_(nullptr) {}
|
||||
Safepoint::Safepoint(Heap* heap)
|
||||
: heap_(heap), local_heaps_head_(nullptr), is_active_(false) {}
|
||||
|
||||
void Safepoint::Start() { StopThreads(); }
|
||||
|
||||
@ -35,9 +37,13 @@ void Safepoint::StopThreads() {
|
||||
current->state_change_.Wait(¤t->state_mutex_);
|
||||
}
|
||||
}
|
||||
|
||||
is_active_ = true;
|
||||
}
|
||||
|
||||
void Safepoint::ResumeThreads() {
|
||||
is_active_ = false;
|
||||
|
||||
for (LocalHeap* current = local_heaps_head_; current;
|
||||
current = current->next_) {
|
||||
current->state_mutex_.Unlock();
|
||||
@ -124,6 +130,7 @@ bool Safepoint::ContainsAnyLocalHeap() {
|
||||
}
|
||||
|
||||
void Safepoint::Iterate(RootVisitor* visitor) {
|
||||
DCHECK(IsActive());
|
||||
for (LocalHeap* current = local_heaps_head_; current;
|
||||
current = current->next_) {
|
||||
current->handles()->Iterate(visitor);
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include "src/base/platform/condition-variable.h"
|
||||
#include "src/base/platform/mutex.h"
|
||||
#include "src/handles/persistent-handles.h"
|
||||
#include "src/objects/visitors.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -32,6 +34,8 @@ class Safepoint {
|
||||
void Start();
|
||||
void End();
|
||||
|
||||
bool IsActive() { return is_active_; }
|
||||
|
||||
private:
|
||||
class Barrier {
|
||||
base::Mutex mutex_;
|
||||
@ -58,8 +62,11 @@ class Safepoint {
|
||||
base::Mutex local_heaps_mutex_;
|
||||
LocalHeap* local_heaps_head_;
|
||||
|
||||
bool is_active_;
|
||||
|
||||
friend class SafepointScope;
|
||||
friend class LocalHeap;
|
||||
friend class PersistentHandles;
|
||||
};
|
||||
|
||||
class SafepointScope {
|
||||
|
@ -228,6 +228,7 @@ v8_source_set("cctest_sources") {
|
||||
"test-object.cc",
|
||||
"test-orderedhashtable.cc",
|
||||
"test-parsing.cc",
|
||||
"test-persistent-handles.cc",
|
||||
"test-platform.cc",
|
||||
"test-profile-generator.cc",
|
||||
"test-random-number-generator.cc",
|
||||
|
114
test/cctest/test-persistent-handles.cc
Normal file
114
test/cctest/test-persistent-handles.cc
Normal file
@ -0,0 +1,114 @@
|
||||
// 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/handles/persistent-handles.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 {
|
||||
|
||||
static constexpr int kNumHandles = kHandleBlockSize * 2 + kHandleBlockSize / 2;
|
||||
|
||||
class PersistentHandlesThread final : public v8::base::Thread {
|
||||
public:
|
||||
PersistentHandlesThread(Heap* heap, std::vector<Handle<HeapNumber>> handles,
|
||||
std::unique_ptr<PersistentHandles> ph, Address object,
|
||||
base::Semaphore* sema_started,
|
||||
base::Semaphore* sema_gc_finished)
|
||||
: v8::base::Thread(base::Thread::Options("ThreadWithLocalHeap")),
|
||||
heap_(heap),
|
||||
handles_(std::move(handles)),
|
||||
ph_(std::move(ph)),
|
||||
object_(object),
|
||||
sema_started_(sema_started),
|
||||
sema_gc_finished_(sema_gc_finished) {}
|
||||
|
||||
void Run() override {
|
||||
LocalHeap local_heap(heap_, std::move(ph_));
|
||||
LocalHandleScope scope(&local_heap);
|
||||
|
||||
for (int i = 0; i < kNumHandles; i++) {
|
||||
handles_.push_back(
|
||||
Handle<HeapNumber>::cast(local_heap.NewPersistentHandle(object_)));
|
||||
}
|
||||
|
||||
sema_started_->Signal();
|
||||
|
||||
{
|
||||
ParkedScope scope(&local_heap);
|
||||
sema_gc_finished_->Wait();
|
||||
}
|
||||
|
||||
for (Handle<HeapNumber> handle : handles_) {
|
||||
CHECK_EQ(42.0, handle->value());
|
||||
}
|
||||
|
||||
CHECK_EQ(handles_.size(), kNumHandles * 2);
|
||||
|
||||
CHECK(!ph_);
|
||||
ph_ = local_heap.DetachPersistentHandles();
|
||||
}
|
||||
|
||||
Heap* heap_;
|
||||
std::vector<Handle<HeapNumber>> handles_;
|
||||
std::unique_ptr<PersistentHandles> ph_;
|
||||
Address object_;
|
||||
base::Semaphore* sema_started_;
|
||||
base::Semaphore* sema_gc_finished_;
|
||||
};
|
||||
|
||||
TEST(CreatePersistentHandles) {
|
||||
CcTest::InitializeVM();
|
||||
FLAG_local_heaps = true;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
|
||||
Address object = kNullAddress;
|
||||
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
|
||||
std::vector<Handle<HeapNumber>> handles;
|
||||
|
||||
HandleScope handle_scope(isolate);
|
||||
Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(42.0);
|
||||
|
||||
object = number->ptr();
|
||||
|
||||
for (int i = 0; i < kNumHandles; i++) {
|
||||
handles.push_back(Handle<HeapNumber>::cast(ph->NewHandle(object)));
|
||||
}
|
||||
|
||||
base::Semaphore sema_started(0);
|
||||
base::Semaphore sema_gc_finished(0);
|
||||
|
||||
// pass persistent handles to background thread
|
||||
std::unique_ptr<PersistentHandlesThread> thread(new PersistentHandlesThread(
|
||||
isolate->heap(), std::move(handles), std::move(ph), object, &sema_started,
|
||||
&sema_gc_finished));
|
||||
CHECK(thread->Start());
|
||||
|
||||
sema_started.Wait();
|
||||
|
||||
CcTest::CollectAllGarbage();
|
||||
sema_gc_finished.Signal();
|
||||
|
||||
thread->Join();
|
||||
|
||||
// get persistent handles back to main thread
|
||||
ph = std::move(thread->ph_);
|
||||
ph->NewHandle(number->ptr());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
Loading…
Reference in New Issue
Block a user