LCOV - code coverage report
Current view: top level - test/cctest/heap - test-embedder-tracing.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 276 276 100.0 %
Date: 2019-02-19 Functions: 43 46 93.5 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <unordered_map>
       6             : #include <vector>
       7             : 
       8             : #include "include/v8.h"
       9             : #include "src/api-inl.h"
      10             : #include "src/heap/heap-inl.h"
      11             : #include "src/objects-inl.h"
      12             : #include "src/objects/module.h"
      13             : #include "src/objects/script.h"
      14             : #include "src/objects/shared-function-info.h"
      15             : #include "test/cctest/cctest.h"
      16             : #include "test/cctest/heap/heap-utils.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : namespace heap {
      21             : 
      22             : namespace {
      23             : 
      24          35 : v8::Local<v8::Object> ConstructTraceableJSApiObject(
      25             :     v8::Local<v8::Context> context, void* first_field, void* second_field) {
      26          35 :   v8::EscapableHandleScope scope(context->GetIsolate());
      27             :   v8::Local<v8::FunctionTemplate> function_t =
      28          35 :       v8::FunctionTemplate::New(context->GetIsolate());
      29          35 :   v8::Local<v8::ObjectTemplate> instance_t = function_t->InstanceTemplate();
      30          35 :   instance_t->SetInternalFieldCount(2);
      31             :   v8::Local<v8::Function> function =
      32          35 :       function_t->GetFunction(context).ToLocalChecked();
      33             :   v8::Local<v8::Object> instance =
      34             :       function->NewInstance(context).ToLocalChecked();
      35          35 :   instance->SetAlignedPointerInInternalField(0, first_field);
      36          35 :   instance->SetAlignedPointerInInternalField(1, second_field);
      37          35 :   CHECK(!instance.IsEmpty());
      38             :   i::Handle<i::JSReceiver> js_obj = v8::Utils::OpenHandle(*instance);
      39          35 :   CHECK_EQ(i::JS_API_OBJECT_TYPE, js_obj->map()->instance_type());
      40          35 :   return scope.Escape(instance);
      41             : }
      42             : 
      43         140 : class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer {
      44             :  public:
      45         140 :   TestEmbedderHeapTracer() = default;
      46             : 
      47          15 :   void RegisterV8References(
      48          15 :       const std::vector<std::pair<void*, void*>>& embedder_fields) final {
      49             :     registered_from_v8_.insert(registered_from_v8_.end(),
      50          15 :                                embedder_fields.begin(), embedder_fields.end());
      51          15 :   }
      52             : 
      53             :   void AddReferenceForTracing(v8::TracedGlobal<v8::Object>* global) {
      54           5 :     to_register_with_v8_.push_back(global);
      55             :   }
      56             : 
      57         135 :   bool AdvanceTracing(double deadline_in_ms) final {
      58         275 :     for (auto global : to_register_with_v8_) {
      59           5 :       RegisterEmbedderReference(global->As<v8::Value>());
      60             :     }
      61             :     to_register_with_v8_.clear();
      62         135 :     return true;
      63             :   }
      64             : 
      65         450 :   bool IsTracingDone() final { return to_register_with_v8_.empty(); }
      66             : 
      67          45 :   void TracePrologue() final {}
      68          45 :   void TraceEpilogue() final {}
      69          45 :   void EnterFinalPause(EmbedderStackState) final {}
      70             : 
      71             :   bool IsRegisteredFromV8(void* first_field) const {
      72          30 :     for (auto pair : registered_from_v8_) {
      73          15 :       if (pair.first == first_field) return true;
      74             :     }
      75             :     return false;
      76             :   }
      77             : 
      78             :   void ConsiderTracedGlobalAsRoot(bool value) {
      79          20 :     consider_traced_global_as_root_ = value;
      80             :   }
      81             : 
      82          15 :   bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) final {
      83          15 :     return consider_traced_global_as_root_;
      84             :   }
      85             : 
      86             :  private:
      87             :   std::vector<std::pair<void*, void*>> registered_from_v8_;
      88             :   std::vector<v8::TracedGlobal<v8::Object>*> to_register_with_v8_;
      89             :   bool consider_traced_global_as_root_ = true;
      90             : };
      91             : 
      92             : class TemporaryEmbedderHeapTracerScope {
      93             :  public:
      94             :   TemporaryEmbedderHeapTracerScope(v8::Isolate* isolate,
      95             :                                    EmbedderHeapTracer* tracer)
      96             :       : isolate_(isolate) {
      97          70 :     isolate_->SetEmbedderHeapTracer(tracer);
      98             :   }
      99             : 
     100             :   ~TemporaryEmbedderHeapTracerScope() {
     101          70 :     isolate_->SetEmbedderHeapTracer(nullptr);
     102             :   }
     103             : 
     104             :  private:
     105             :   v8::Isolate* const isolate_;
     106             : };
     107             : 
     108             : }  // namespace
     109             : 
     110       25880 : TEST(V8RegisteringEmbedderReference) {
     111             :   // Tests that wrappers are properly registered with the embedder heap
     112             :   // tracer.
     113             :   ManualGCScope manual_gc;
     114           5 :   CcTest::InitializeVM();
     115           5 :   v8::Isolate* isolate = CcTest::isolate();
     116           5 :   TestEmbedderHeapTracer tracer;
     117             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     118          10 :   v8::HandleScope scope(isolate);
     119           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     120             :   v8::Context::Scope context_scope(context);
     121             : 
     122             :   void* first_field = reinterpret_cast<void*>(0x2);
     123             :   v8::Local<v8::Object> api_object =
     124           5 :       ConstructTraceableJSApiObject(context, first_field, nullptr);
     125           5 :   CHECK(!api_object.IsEmpty());
     126           5 :   CcTest::CollectGarbage(i::OLD_SPACE);
     127           5 :   CHECK(tracer.IsRegisteredFromV8(first_field));
     128           5 : }
     129             : 
     130       25880 : TEST(EmbedderRegisteringV8Reference) {
     131             :   // Tests that references that are registered by the embedder heap tracer are
     132             :   // considered live by V8.
     133             :   ManualGCScope manual_gc;
     134           5 :   CcTest::InitializeVM();
     135           5 :   v8::Isolate* isolate = CcTest::isolate();
     136           5 :   TestEmbedderHeapTracer tracer;
     137             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     138          10 :   v8::HandleScope scope(isolate);
     139           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     140             :   v8::Context::Scope context_scope(context);
     141             : 
     142          10 :   v8::TracedGlobal<v8::Object> g;
     143             :   {
     144           5 :     v8::HandleScope inner_scope(isolate);
     145             :     v8::Local<v8::Object> o =
     146           5 :         v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     147           5 :     g.Reset(isolate, o);
     148             :   }
     149             :   tracer.AddReferenceForTracing(&g);
     150           5 :   CcTest::CollectGarbage(i::OLD_SPACE);
     151           5 :   CHECK(!g.IsEmpty());
     152           5 : }
     153             : 
     154             : namespace {
     155             : 
     156           5 : void ResurrectingFinalizer(
     157           5 :     const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
     158             :   data.GetParameter()->ClearWeak();
     159           5 : }
     160             : 
     161             : }  // namespace
     162             : 
     163       25880 : TEST(TracingInRevivedSubgraph) {
     164             :   // Tests that wrappers are traced when they are contained with in a subgraph
     165             :   // that is revived by a finalizer.
     166             :   ManualGCScope manual_gc;
     167           5 :   CcTest::InitializeVM();
     168           5 :   v8::Isolate* isolate = CcTest::isolate();
     169           5 :   TestEmbedderHeapTracer tracer;
     170             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     171          10 :   v8::HandleScope scope(isolate);
     172           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     173             :   v8::Context::Scope context_scope(context);
     174             : 
     175             :   v8::Global<v8::Object> g;
     176             :   void* first_field = reinterpret_cast<void*>(0x4);
     177             :   {
     178           5 :     v8::HandleScope inner_scope(isolate);
     179             :     v8::Local<v8::Object> api_object =
     180           5 :         ConstructTraceableJSApiObject(context, first_field, nullptr);
     181           5 :     CHECK(!api_object.IsEmpty());
     182             :     v8::Local<v8::Object> o =
     183           5 :         v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     184          15 :     o->Set(context, v8_str("link"), api_object).FromJust();
     185             :     g.Reset(isolate, o);
     186           5 :     g.SetWeak(&g, ResurrectingFinalizer, v8::WeakCallbackType::kFinalizer);
     187             :   }
     188           5 :   CcTest::CollectGarbage(i::OLD_SPACE);
     189           5 :   CHECK(tracer.IsRegisteredFromV8(first_field));
     190           5 : }
     191             : 
     192       25880 : TEST(TracingInEphemerons) {
     193             :   // Tests that wrappers that are part of ephemerons are traced.
     194             :   ManualGCScope manual_gc;
     195           5 :   CcTest::InitializeVM();
     196           5 :   v8::Isolate* isolate = CcTest::isolate();
     197           5 :   TestEmbedderHeapTracer tracer;
     198             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     199          10 :   v8::HandleScope scope(isolate);
     200           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     201             :   v8::Context::Scope context_scope(context);
     202             : 
     203             :   v8::Local<v8::Object> key =
     204           5 :       v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     205             :   void* first_field = reinterpret_cast<void*>(0x8);
     206             :   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
     207           5 :   Handle<JSWeakMap> weak_map = i_isolate->factory()->NewJSWeakMap();
     208             :   {
     209           5 :     v8::HandleScope inner_scope(isolate);
     210             :     v8::Local<v8::Object> api_object =
     211           5 :         ConstructTraceableJSApiObject(context, first_field, nullptr);
     212           5 :     CHECK(!api_object.IsEmpty());
     213             :     Handle<JSObject> js_key =
     214             :         handle(JSObject::cast(*v8::Utils::OpenHandle(*key)), i_isolate);
     215             :     Handle<JSReceiver> js_api_object = v8::Utils::OpenHandle(*api_object);
     216          10 :     int32_t hash = js_key->GetOrCreateHash(i_isolate)->value();
     217           5 :     JSWeakCollection::Set(weak_map, js_key, js_api_object, hash);
     218             :   }
     219           5 :   CcTest::CollectGarbage(i::OLD_SPACE);
     220           5 :   CHECK(tracer.IsRegisteredFromV8(first_field));
     221           5 : }
     222             : 
     223       25880 : TEST(FinalizeTracingIsNoopWhenNotMarking) {
     224             :   ManualGCScope manual_gc;
     225           5 :   CcTest::InitializeVM();
     226           5 :   v8::Isolate* isolate = CcTest::isolate();
     227             :   Isolate* i_isolate = CcTest::i_isolate();
     228           5 :   TestEmbedderHeapTracer tracer;
     229             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     230             : 
     231             :   // Finalize a potentially running garbage collection.
     232             :   i_isolate->heap()->CollectGarbage(OLD_SPACE,
     233           5 :                                     GarbageCollectionReason::kTesting);
     234           5 :   CHECK(i_isolate->heap()->incremental_marking()->IsStopped());
     235             : 
     236           5 :   int gc_counter = i_isolate->heap()->gc_count();
     237           5 :   tracer.FinalizeTracing();
     238           5 :   CHECK(i_isolate->heap()->incremental_marking()->IsStopped());
     239           5 :   CHECK_EQ(gc_counter, i_isolate->heap()->gc_count());
     240           5 : }
     241             : 
     242       25880 : TEST(FinalizeTracingWhenMarking) {
     243             :   ManualGCScope manual_gc;
     244           5 :   CcTest::InitializeVM();
     245           5 :   v8::Isolate* isolate = CcTest::isolate();
     246             :   Isolate* i_isolate = CcTest::i_isolate();
     247           5 :   TestEmbedderHeapTracer tracer;
     248             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     249             : 
     250             :   // Finalize a potentially running garbage collection.
     251             :   i_isolate->heap()->CollectGarbage(OLD_SPACE,
     252           5 :                                     GarbageCollectionReason::kTesting);
     253          10 :   if (i_isolate->heap()->mark_compact_collector()->sweeping_in_progress()) {
     254           5 :     i_isolate->heap()->mark_compact_collector()->EnsureSweepingCompleted();
     255             :   }
     256           5 :   CHECK(i_isolate->heap()->incremental_marking()->IsStopped());
     257             : 
     258             :   i::IncrementalMarking* marking = i_isolate->heap()->incremental_marking();
     259           5 :   marking->Start(i::GarbageCollectionReason::kTesting);
     260             :   // Sweeping is not runing so we should immediately start marking.
     261           5 :   CHECK(marking->IsMarking());
     262           5 :   tracer.FinalizeTracing();
     263           5 :   CHECK(marking->IsStopped());
     264           5 : }
     265             : 
     266       25880 : TEST(GarbageCollectionForTesting) {
     267             :   ManualGCScope manual_gc;
     268           5 :   i::FLAG_expose_gc = true;
     269           5 :   CcTest::InitializeVM();
     270           5 :   v8::Isolate* isolate = CcTest::isolate();
     271             :   Isolate* i_isolate = CcTest::i_isolate();
     272           5 :   TestEmbedderHeapTracer tracer;
     273             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     274             : 
     275           5 :   int saved_gc_counter = i_isolate->heap()->gc_count();
     276           5 :   tracer.GarbageCollectionForTesting(EmbedderHeapTracer::kUnknown);
     277          10 :   CHECK_GT(i_isolate->heap()->gc_count(), saved_gc_counter);
     278           5 : }
     279             : 
     280             : namespace {
     281             : 
     282          35 : void ConstructJSObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
     283             :                        v8::TracedGlobal<v8::Object>* global) {
     284          35 :   v8::HandleScope scope(isolate);
     285          35 :   v8::Local<v8::Object> object(v8::Object::New(isolate));
     286          35 :   CHECK(!object.IsEmpty());
     287          35 :   *global = v8::TracedGlobal<v8::Object>(isolate, object);
     288          35 :   CHECK(!global->IsEmpty());
     289          35 : }
     290             : 
     291          20 : void ConstructJSApiObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
     292             :                           v8::TracedGlobal<v8::Object>* global) {
     293          20 :   v8::HandleScope scope(isolate);
     294             :   v8::Local<v8::Object> object(
     295          20 :       ConstructTraceableJSApiObject(context, nullptr, nullptr));
     296          20 :   CHECK(!object.IsEmpty());
     297          20 :   *global = v8::TracedGlobal<v8::Object>(isolate, object);
     298          20 :   CHECK(!global->IsEmpty());
     299          20 : }
     300             : 
     301             : enum class SurvivalMode { kSurvives, kDies };
     302             : 
     303             : template <typename ModifierFunction, typename ConstructTracedGlobalFunction>
     304          30 : void TracedGlobalTest(v8::Isolate* isolate,
     305             :                       ConstructTracedGlobalFunction construct_function,
     306             :                       ModifierFunction modifier_function, void (*gc_function)(),
     307             :                       SurvivalMode survives) {
     308          30 :   v8::HandleScope scope(isolate);
     309          30 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     310             :   v8::Context::Scope context_scope(context);
     311             : 
     312          60 :   v8::TracedGlobal<v8::Object> global;
     313          30 :   construct_function(isolate, context, &global);
     314          30 :   CHECK(InYoungGeneration(isolate, global));
     315           5 :   modifier_function(global);
     316          30 :   gc_function();
     317          50 :   CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !global.IsEmpty());
     318          70 :   CHECK_IMPLIES(survives == SurvivalMode::kDies, global.IsEmpty());
     319          30 : }
     320             : 
     321             : }  // namespace
     322             : 
     323       25880 : TEST(TracedGlobalReset) {
     324           5 :   CcTest::InitializeVM();
     325           5 :   v8::Isolate* isolate = CcTest::isolate();
     326           5 :   v8::HandleScope scope(isolate);
     327             : 
     328          10 :   v8::TracedGlobal<v8::Object> traced;
     329           5 :   ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced);
     330           5 :   CHECK(!traced.IsEmpty());
     331             :   traced.Reset();
     332          10 :   CHECK(traced.IsEmpty());
     333           5 : }
     334             : 
     335       25880 : TEST(TracedGlobalInStdVector) {
     336             :   ManualGCScope manual_gc;
     337           5 :   CcTest::InitializeVM();
     338           5 :   v8::Isolate* isolate = CcTest::isolate();
     339          10 :   v8::HandleScope scope(isolate);
     340             : 
     341           5 :   std::vector<v8::TracedGlobal<v8::Object>> vec;
     342             :   {
     343           5 :     v8::HandleScope scope(isolate);
     344           5 :     vec.emplace_back(isolate, v8::Object::New(isolate));
     345             :   }
     346          10 :   CHECK(!vec[0].IsEmpty());
     347           5 :   InvokeMarkSweep();
     348          10 :   CHECK(vec[0].IsEmpty());
     349           5 : }
     350             : 
     351       25880 : TEST(TracedGlobalInStdUnorderedMap) {
     352             :   ManualGCScope manual_gc;
     353           5 :   CcTest::InitializeVM();
     354           5 :   v8::Isolate* isolate = CcTest::isolate();
     355          10 :   v8::HandleScope scope(isolate);
     356             : 
     357           5 :   std::unordered_map<int, v8::TracedGlobal<v8::Object>> map;
     358             :   {
     359           5 :     v8::HandleScope scope(isolate);
     360             :     map.emplace(std::piecewise_construct, std::forward_as_tuple(1),
     361          15 :                 std::forward_as_tuple(isolate, v8::Object::New(isolate)));
     362             :   }
     363          10 :   CHECK(!map[1].IsEmpty());
     364           5 :   InvokeMarkSweep();
     365          10 :   CHECK(map[1].IsEmpty());
     366           5 : }
     367             : 
     368       25880 : TEST(TracedGlobalToUnmodifiedJSObjectDiesOnMarkSweep) {
     369           5 :   CcTest::InitializeVM();
     370             :   TracedGlobalTest(
     371             :       CcTest::isolate(), ConstructJSObject,
     372             :       [](const TracedGlobal<v8::Object>& global) {}, InvokeMarkSweep,
     373           5 :       SurvivalMode::kDies);
     374           5 : }
     375             : 
     376       25880 : TEST(TracedGlobalToUnmodifiedJSObjectSurvivesMarkSweepWhenHeldAliveOtherwise) {
     377           5 :   CcTest::InitializeVM();
     378           5 :   v8::Isolate* isolate = CcTest::isolate();
     379             :   v8::Global<v8::Object> strong_global;
     380             :   TracedGlobalTest(
     381             :       CcTest::isolate(), ConstructJSObject,
     382           5 :       [isolate, &strong_global](const TracedGlobal<v8::Object>& global) {
     383           5 :         v8::HandleScope scope(isolate);
     384          20 :         strong_global = v8::Global<v8::Object>(isolate, global.Get(isolate));
     385           5 :       },
     386           5 :       InvokeMarkSweep, SurvivalMode::kSurvives);
     387           5 : }
     388             : 
     389       25880 : TEST(TracedGlobalToUnmodifiedJSObjectSurvivesScavenge) {
     390             :   ManualGCScope manual_gc;
     391           5 :   CcTest::InitializeVM();
     392             :   TracedGlobalTest(
     393             :       CcTest::isolate(), ConstructJSObject,
     394             :       [](const TracedGlobal<v8::Object>& global) {}, InvokeScavenge,
     395           5 :       SurvivalMode::kSurvives);
     396           5 : }
     397             : 
     398       25880 : TEST(TracedGlobalToUnmodifiedJSObjectSurvivesScavengeWhenExcludedFromRoots) {
     399             :   ManualGCScope manual_gc;
     400           5 :   CcTest::InitializeVM();
     401           5 :   v8::Isolate* isolate = CcTest::isolate();
     402           5 :   TestEmbedderHeapTracer tracer;
     403             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     404             :   tracer.ConsiderTracedGlobalAsRoot(false);
     405             :   TracedGlobalTest(
     406             :       CcTest::isolate(), ConstructJSObject,
     407             :       [](const TracedGlobal<v8::Object>& global) {}, InvokeScavenge,
     408           5 :       SurvivalMode::kSurvives);
     409           5 : }
     410             : 
     411       25880 : TEST(TracedGlobalToUnmodifiedJSApiObjectSurvivesScavengePerDefault) {
     412             :   ManualGCScope manual_gc;
     413           5 :   CcTest::InitializeVM();
     414           5 :   v8::Isolate* isolate = CcTest::isolate();
     415           5 :   TestEmbedderHeapTracer tracer;
     416             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     417             :   tracer.ConsiderTracedGlobalAsRoot(true);
     418             :   TracedGlobalTest(
     419             :       CcTest::isolate(), ConstructJSApiObject,
     420             :       [](const TracedGlobal<v8::Object>& global) {}, InvokeScavenge,
     421           5 :       SurvivalMode::kSurvives);
     422           5 : }
     423             : 
     424       25880 : TEST(TracedGlobalToUnmodifiedJSApiObjectDiesOnScavengeWhenExcludedFromRoots) {
     425             :   ManualGCScope manual_gc;
     426           5 :   CcTest::InitializeVM();
     427           5 :   v8::Isolate* isolate = CcTest::isolate();
     428           5 :   TestEmbedderHeapTracer tracer;
     429             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     430             :   tracer.ConsiderTracedGlobalAsRoot(false);
     431             :   TracedGlobalTest(
     432             :       CcTest::isolate(), ConstructJSApiObject,
     433             :       [](const TracedGlobal<v8::Object>& global) {}, InvokeScavenge,
     434           5 :       SurvivalMode::kDies);
     435           5 : }
     436             : 
     437       25880 : TEST(TracedGlobalWrapperClassId) {
     438             :   ManualGCScope manual_gc;
     439           5 :   CcTest::InitializeVM();
     440           5 :   v8::Isolate* isolate = CcTest::isolate();
     441          10 :   v8::HandleScope scope(isolate);
     442           5 :   TestEmbedderHeapTracer tracer;
     443             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     444             : 
     445          10 :   v8::TracedGlobal<v8::Object> traced;
     446           5 :   ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced);
     447           5 :   CHECK_EQ(0, traced.WrapperClassId());
     448             :   traced.SetWrapperClassId(17);
     449           5 :   CHECK_EQ(17, traced.WrapperClassId());
     450           5 : }
     451             : 
     452             : namespace {
     453             : 
     454             : class TracedGlobalVisitor final
     455             :     : public v8::EmbedderHeapTracer::TracedGlobalHandleVisitor {
     456             :  public:
     457           5 :   ~TracedGlobalVisitor() override = default;
     458           5 :   void VisitTracedGlobalHandle(const TracedGlobal<Value>& value) final {
     459           5 :     if (value.WrapperClassId() == 57) {
     460           5 :       count_++;
     461             :     }
     462           5 :   }
     463             : 
     464             :   size_t count() const { return count_; }
     465             : 
     466             :  private:
     467             :   size_t count_ = 0;
     468             : };
     469             : 
     470             : }  // namespace
     471             : 
     472       25880 : TEST(TracedGlobalIteration) {
     473             :   ManualGCScope manual_gc;
     474           5 :   CcTest::InitializeVM();
     475           5 :   v8::Isolate* isolate = CcTest::isolate();
     476          10 :   v8::HandleScope scope(isolate);
     477           5 :   TestEmbedderHeapTracer tracer;
     478             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     479             : 
     480          10 :   v8::TracedGlobal<v8::Object> traced;
     481           5 :   ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced);
     482           5 :   CHECK(!traced.IsEmpty());
     483             :   traced.SetWrapperClassId(57);
     484           5 :   TracedGlobalVisitor visitor;
     485             :   {
     486           5 :     v8::HandleScope scope(isolate);
     487           5 :     tracer.IterateTracedGlobalHandles(&visitor);
     488             :   }
     489          10 :   CHECK_EQ(1, visitor.count());
     490           5 : }
     491             : 
     492             : namespace {
     493             : 
     494          10 : void FinalizationCallback(const WeakCallbackInfo<void>& data) {
     495             :   v8::TracedGlobal<v8::Object>* traced =
     496             :       reinterpret_cast<v8::TracedGlobal<v8::Object>*>(data.GetParameter());
     497          10 :   CHECK_EQ(reinterpret_cast<void*>(0x4), data.GetInternalField(0));
     498          10 :   CHECK_EQ(reinterpret_cast<void*>(0x8), data.GetInternalField(1));
     499             :   traced->Reset();
     500          10 : }
     501             : 
     502             : }  // namespace
     503             : 
     504       25880 : TEST(TracedGlobalSetFinalizationCallbackScavenge) {
     505             :   ManualGCScope manual_gc;
     506           5 :   CcTest::InitializeVM();
     507           5 :   v8::Isolate* isolate = CcTest::isolate();
     508          10 :   v8::HandleScope scope(isolate);
     509           5 :   TestEmbedderHeapTracer tracer;
     510             :   tracer.ConsiderTracedGlobalAsRoot(false);
     511             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     512             : 
     513          10 :   v8::TracedGlobal<v8::Object> traced;
     514           5 :   ConstructJSApiObject(isolate, isolate->GetCurrentContext(), &traced);
     515           5 :   CHECK(!traced.IsEmpty());
     516             :   {
     517           5 :     v8::HandleScope scope(isolate);
     518             :     auto local = traced.Get(isolate);
     519           5 :     local->SetAlignedPointerInInternalField(0, reinterpret_cast<void*>(0x4));
     520           5 :     local->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0x8));
     521             :   }
     522             :   traced.SetFinalizationCallback(&traced, FinalizationCallback);
     523           5 :   heap::InvokeScavenge();
     524           5 :   CHECK(traced.IsEmpty());
     525           5 : }
     526             : 
     527       25880 : TEST(TracedGlobalSetFinalizationCallbackMarkSweep) {
     528             :   ManualGCScope manual_gc;
     529           5 :   CcTest::InitializeVM();
     530           5 :   v8::Isolate* isolate = CcTest::isolate();
     531          10 :   v8::HandleScope scope(isolate);
     532           5 :   TestEmbedderHeapTracer tracer;
     533             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     534             : 
     535          10 :   v8::TracedGlobal<v8::Object> traced;
     536           5 :   ConstructJSApiObject(isolate, isolate->GetCurrentContext(), &traced);
     537           5 :   CHECK(!traced.IsEmpty());
     538             :   {
     539           5 :     v8::HandleScope scope(isolate);
     540             :     auto local = traced.Get(isolate);
     541           5 :     local->SetAlignedPointerInInternalField(0, reinterpret_cast<void*>(0x4));
     542           5 :     local->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0x8));
     543             :   }
     544             :   traced.SetFinalizationCallback(&traced, FinalizationCallback);
     545           5 :   heap::InvokeMarkSweep();
     546           5 :   CHECK(traced.IsEmpty());
     547           5 : }
     548             : 
     549             : }  // namespace heap
     550             : }  // namespace internal
     551       77625 : }  // namespace v8

Generated by: LCOV version 1.10