LCOV - code coverage report
Current view: top level - test/cctest/heap - test-embedder-tracing.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 290 290 100.0 %
Date: 2019-04-17 Functions: 45 48 93.8 %

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

Generated by: LCOV version 1.10