| // 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/common/globals.h" |
| #include "src/handles/handles-inl.h" |
| #include "src/handles/local-handles-inl.h" |
| #include "src/handles/local-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 { |
| |
| namespace { |
| |
| 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_, ThreadKind::kBackground); |
| UnparkedScope unparked_scope(&local_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) { |
| heap::EnsureFlagLocalHeapsEnabled(); |
| CcTest::InitializeVM(); |
| 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(); |
| } |
| |
| TEST(CreateLocalHandlesWithoutLocalHandleScope) { |
| heap::EnsureFlagLocalHeapsEnabled(); |
| CcTest::InitializeVM(); |
| Isolate* isolate = CcTest::i_isolate(); |
| |
| { |
| LocalHeap local_heap(isolate->heap(), ThreadKind::kMain); |
| UnparkedScope scope(&local_heap); |
| handle(Smi::FromInt(17), &local_heap); |
| } |
| } |
| |
| TEST(DereferenceLocalHandle) { |
| heap::EnsureFlagLocalHeapsEnabled(); |
| CcTest::InitializeVM(); |
| Isolate* isolate = CcTest::i_isolate(); |
| |
| // Create a PersistentHandle to create the LocalHandle, and thus not have a |
| // HandleScope present to override the LocalHandleScope. |
| std::unique_ptr<PersistentHandles> phs = isolate->NewPersistentHandles(); |
| Handle<HeapNumber> ph; |
| { |
| HandleScope handle_scope(isolate); |
| Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(42.0); |
| ph = phs->NewHandle(number); |
| } |
| { |
| LocalHeap local_heap(isolate->heap(), ThreadKind::kMain, std::move(phs)); |
| UnparkedScope unparked_scope(&local_heap); |
| LocalHandleScope scope(&local_heap); |
| Handle<HeapNumber> local_number = handle(*ph, &local_heap); |
| CHECK_EQ(42, local_number->value()); |
| DisallowHandleDereference disallow_scope; |
| CHECK_EQ(42, local_number->value()); |
| } |
| } |
| |
| } // anonymous namespace |
| |
| } // namespace internal |
| } // namespace v8 |