text: // Copyright 2017 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 <stdlib.h>
  
  #include "src/v8.h"
  
  #include "src/heap/concurrent-marking.h"
  #include "src/heap/heap-inl.h"
  #include "src/heap/heap.h"
  #include "src/heap/mark-compact.h"
  #include "src/heap/worklist.h"
  #include "test/cctest/cctest.h"
  #include "test/cctest/heap/heap-utils.h"
  
  namespace v8 {
  namespace internal {
  namespace heap {
  
  void PublishSegment(ConcurrentMarking::MarkingWorklist* worklist,
                      HeapObject* object) {
    for (size_t i = 0; i <= ConcurrentMarking::MarkingWorklist::kSegmentCapacity;
         i++) {
      worklist->Push(0, object);
    }
    CHECK(worklist->Pop(0, &object));
  }
  
  TEST(ConcurrentMarking) {
    if (!i::FLAG_concurrent_marking) return;
    CcTest::InitializeVM();
    Heap* heap = CcTest::heap();
    CcTest::CollectAllGarbage();
    if (!heap->incremental_marking()->IsStopped()) return;
    MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
    if (collector->sweeping_in_progress()) {
      collector->EnsureSweepingCompleted();
    }
  
    ConcurrentMarking::MarkingWorklist shared, bailout, on_hold;
    ConcurrentMarking::EmbedderTracingWorklist embedder_objects;
    WeakObjects weak_objects;
    ConcurrentMarking* concurrent_marking = new ConcurrentMarking(
        heap, &shared, &bailout, &on_hold, &weak_objects, &embedder_objects);
    PublishSegment(&shared, ReadOnlyRoots(heap).undefined_value());
    concurrent_marking->ScheduleTasks();
    concurrent_marking->Stop(
        ConcurrentMarking::StopRequest::COMPLETE_TASKS_FOR_TESTING);
    delete concurrent_marking;
  }
  
  TEST(ConcurrentMarkingReschedule) {
    if (!i::FLAG_concurrent_marking) return;
    CcTest::InitializeVM();
    Heap* heap = CcTest::heap();
    CcTest::CollectAllGarbage();
    if (!heap->incremental_marking()->IsStopped()) return;
    MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
    if (collector->sweeping_in_progress()) {
      collector->EnsureSweepingCompleted();
    }
  
    ConcurrentMarking::MarkingWorklist shared, bailout, on_hold;
    ConcurrentMarking::EmbedderTracingWorklist embedder_objects;
    WeakObjects weak_objects;
    ConcurrentMarking* concurrent_marking = new ConcurrentMarking(
        heap, &shared, &bailout, &on_hold, &weak_objects, &embedder_objects);
    PublishSegment(&shared, ReadOnlyRoots(heap).undefined_value());
    concurrent_marking->ScheduleTasks();
    concurrent_marking->Stop(
        ConcurrentMarking::StopRequest::COMPLETE_ONGOING_TASKS);
    PublishSegment(&shared, ReadOnlyRoots(heap).undefined_value());
    concurrent_marking->RescheduleTasksIfNeeded();
    concurrent_marking->Stop(
        ConcurrentMarking::StopRequest::COMPLETE_TASKS_FOR_TESTING);
    delete concurrent_marking;
  }
  
  TEST(ConcurrentMarkingPreemptAndReschedule) {
    if (!i::FLAG_concurrent_marking) return;
    CcTest::InitializeVM();
    Heap* heap = CcTest::heap();
    CcTest::CollectAllGarbage();
    if (!heap->incremental_marking()->IsStopped()) return;
    MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
    if (collector->sweeping_in_progress()) {
      collector->EnsureSweepingCompleted();
    }
  
    ConcurrentMarking::MarkingWorklist shared, bailout, on_hold;
    ConcurrentMarking::EmbedderTracingWorklist embedder_objects;
    WeakObjects weak_objects;
    ConcurrentMarking* concurrent_marking = new ConcurrentMarking(
        heap, &shared, &bailout, &on_hold, &weak_objects, &embedder_objects);
    for (int i = 0; i < 5000; i++)
      PublishSegment(&shared, ReadOnlyRoots(heap).undefined_value());
    concurrent_marking->ScheduleTasks();
    concurrent_marking->Stop(ConcurrentMarking::StopRequest::PREEMPT_TASKS);
    for (int i = 0; i < 5000; i++)
      PublishSegment(&shared, ReadOnlyRoots(heap).undefined_value());
    concurrent_marking->RescheduleTasksIfNeeded();
    concurrent_marking->Stop(
        ConcurrentMarking::StopRequest::COMPLETE_TASKS_FOR_TESTING);
    delete concurrent_marking;
  }
  
  TEST(ConcurrentMarkingMarkedBytes) {
    if (!i::FLAG_concurrent_marking) return;
    CcTest::InitializeVM();
    Isolate* isolate = CcTest::i_isolate();
    Heap* heap = CcTest::heap();
    HandleScope sc(isolate);
    Handle<FixedArray> root = isolate->factory()->NewFixedArray(1000000);
    CcTest::CollectAllGarbage();
    if (!heap->incremental_marking()->IsStopped()) return;
    heap::SimulateIncrementalMarking(heap, false);
    heap->concurrent_marking()->Stop(
        ConcurrentMarking::StopRequest::COMPLETE_TASKS_FOR_TESTING);
    CHECK_GE(heap->concurrent_marking()->TotalMarkedBytes(), root->Size());
  }
  
  UNINITIALIZED_TEST(ConcurrentMarkingStoppedOnTeardown) {
    if (!i::FLAG_concurrent_marking) return;
  
    v8::Isolate::CreateParams create_params;
    create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
    v8::Isolate* isolate = v8::Isolate::New(create_params);
  
    {
      Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
      Factory* factory = i_isolate->factory();
  
      v8::Isolate::Scope isolate_scope(isolate);
      v8::HandleScope handle_scope(isolate);
      v8::Context::New(isolate)->Enter();
  
      for (int i = 0; i < 10000; i++) {
        factory->NewJSWeakMap();
      }
  
      Heap* heap = i_isolate->heap();
      heap::SimulateIncrementalMarking(heap, false);
    }
  
    isolate->Dispose();
  }
  
  }  // namespace heap
  }  // namespace internal
  }  // namespace v8
  