LCOV - code coverage report
Current view: top level - test/cctest/heap - test-embedder-tracing.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 121 122 99.2 %
Date: 2019-01-20 Functions: 18 20 90.0 %

          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 "include/v8.h"
       6             : #include "src/api-inl.h"
       7             : #include "src/objects-inl.h"
       8             : #include "src/objects/module.h"
       9             : #include "src/objects/script.h"
      10             : #include "src/objects/shared-function-info.h"
      11             : #include "test/cctest/cctest.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : namespace heap {
      16             : 
      17             : namespace {
      18             : 
      19          15 : v8::Local<v8::Object> ConstructTraceableJSApiObject(
      20             :     v8::Local<v8::Context> context, void* first_field, void* second_field) {
      21          15 :   v8::EscapableHandleScope scope(context->GetIsolate());
      22             :   v8::Local<v8::FunctionTemplate> function_t =
      23          15 :       v8::FunctionTemplate::New(context->GetIsolate());
      24          15 :   v8::Local<v8::ObjectTemplate> instance_t = function_t->InstanceTemplate();
      25          15 :   instance_t->SetInternalFieldCount(2);
      26             :   v8::Local<v8::Function> function =
      27          15 :       function_t->GetFunction(context).ToLocalChecked();
      28             :   v8::Local<v8::Object> instance =
      29             :       function->NewInstance(context).ToLocalChecked();
      30          15 :   instance->SetAlignedPointerInInternalField(0, first_field);
      31          15 :   instance->SetAlignedPointerInInternalField(1, second_field);
      32          15 :   CHECK(!instance.IsEmpty());
      33             :   i::Handle<i::JSReceiver> js_obj = v8::Utils::OpenHandle(*instance);
      34          15 :   CHECK_EQ(i::JS_API_OBJECT_TYPE, js_obj->map()->instance_type());
      35          15 :   return scope.Escape(instance);
      36             : }
      37             : 
      38          70 : class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer {
      39             :  public:
      40          35 :   explicit TestEmbedderHeapTracer(v8::Isolate* isolate) : isolate_(isolate) {}
      41             : 
      42          15 :   void RegisterV8References(
      43          15 :       const std::vector<std::pair<void*, void*>>& embedder_fields) final {
      44             :     registered_from_v8_.insert(registered_from_v8_.end(),
      45          15 :                                embedder_fields.begin(), embedder_fields.end());
      46          15 :   }
      47             : 
      48             :   void AddReferenceForTracing(v8::Persistent<v8::Object>* persistent) {
      49           5 :     to_register_with_v8_.push_back(persistent);
      50             :   }
      51             : 
      52         120 :   bool AdvanceTracing(double deadline_in_ms) final {
      53         245 :     for (auto persistent : to_register_with_v8_) {
      54           5 :       persistent->RegisterExternalReference(isolate_);
      55             :     }
      56             :     to_register_with_v8_.clear();
      57         120 :     return true;
      58             :   }
      59             : 
      60         400 :   bool IsTracingDone() final { return to_register_with_v8_.empty(); }
      61             : 
      62          40 :   void TracePrologue() final {}
      63          40 :   void TraceEpilogue() final {}
      64           0 :   void AbortTracing() final {}
      65          40 :   void EnterFinalPause(EmbedderStackState) final {}
      66             : 
      67             :   bool IsRegisteredFromV8(void* first_field) const {
      68          30 :     for (auto pair : registered_from_v8_) {
      69          15 :       if (pair.first == first_field) return true;
      70             :     }
      71             :     return false;
      72             :   }
      73             : 
      74             :  private:
      75             :   v8::Isolate* const isolate_;
      76             :   std::vector<std::pair<void*, void*>> registered_from_v8_;
      77             :   std::vector<v8::Persistent<v8::Object>*> to_register_with_v8_;
      78             : };
      79             : 
      80             : class TemporaryEmbedderHeapTracerScope {
      81             :  public:
      82             :   TemporaryEmbedderHeapTracerScope(v8::Isolate* isolate,
      83             :                                    EmbedderHeapTracer* tracer)
      84             :       : isolate_(isolate) {
      85          35 :     isolate_->SetEmbedderHeapTracer(tracer);
      86             :   }
      87             : 
      88             :   ~TemporaryEmbedderHeapTracerScope() {
      89          35 :     isolate_->SetEmbedderHeapTracer(nullptr);
      90             :   }
      91             : 
      92             :  private:
      93             :   v8::Isolate* const isolate_;
      94             : };
      95             : 
      96             : }  // namespace
      97             : 
      98       28342 : TEST(V8RegisteringEmbedderReference) {
      99             :   // Tests that wrappers are properly registered with the embedder heap
     100             :   // tracer.
     101             :   ManualGCScope manual_gc;
     102           5 :   CcTest::InitializeVM();
     103           5 :   v8::Isolate* isolate = CcTest::isolate();
     104           5 :   TestEmbedderHeapTracer tracer(isolate);
     105             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     106          10 :   v8::HandleScope scope(isolate);
     107           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     108             :   v8::Context::Scope context_scope(context);
     109             : 
     110             :   void* first_field = reinterpret_cast<void*>(0x2);
     111             :   v8::Local<v8::Object> api_object =
     112           5 :       ConstructTraceableJSApiObject(context, first_field, nullptr);
     113           5 :   CHECK(!api_object.IsEmpty());
     114           5 :   CcTest::CollectGarbage(i::OLD_SPACE);
     115           5 :   CHECK(tracer.IsRegisteredFromV8(first_field));
     116           5 : }
     117             : 
     118       28342 : TEST(EmbedderRegisteringV8Reference) {
     119             :   // Tests that references that are registered by the embedder heap tracer are
     120             :   // considered live by V8.
     121             :   ManualGCScope manual_gc;
     122           5 :   CcTest::InitializeVM();
     123           5 :   v8::Isolate* isolate = CcTest::isolate();
     124           5 :   TestEmbedderHeapTracer tracer(isolate);
     125             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     126          10 :   v8::HandleScope scope(isolate);
     127           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     128             :   v8::Context::Scope context_scope(context);
     129             : 
     130             :   v8::Persistent<v8::Object> g;
     131             :   {
     132           5 :     v8::HandleScope inner_scope(isolate);
     133             :     v8::Local<v8::Object> o =
     134           5 :         v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     135             :     g.Reset(isolate, o);
     136           5 :     g.SetWeak();
     137             :   }
     138             :   tracer.AddReferenceForTracing(&g);
     139           5 :   CcTest::CollectGarbage(i::OLD_SPACE);
     140           5 :   CHECK(!g.IsEmpty());
     141           5 : }
     142             : 
     143             : namespace {
     144             : 
     145           5 : void ResurrectingFinalizer(
     146           5 :     const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
     147             :   data.GetParameter()->ClearWeak();
     148           5 : }
     149             : 
     150             : }  // namespace
     151             : 
     152       28342 : TEST(TracingInRevivedSubgraph) {
     153             :   // Tests that wrappers are traced when they are contained with in a subgraph
     154             :   // that is revived by a finalizer.
     155             :   ManualGCScope manual_gc;
     156           5 :   CcTest::InitializeVM();
     157           5 :   v8::Isolate* isolate = CcTest::isolate();
     158           5 :   TestEmbedderHeapTracer tracer(isolate);
     159             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     160          10 :   v8::HandleScope scope(isolate);
     161           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     162             :   v8::Context::Scope context_scope(context);
     163             : 
     164             :   v8::Global<v8::Object> g;
     165             :   void* first_field = reinterpret_cast<void*>(0x4);
     166             :   {
     167           5 :     v8::HandleScope inner_scope(isolate);
     168             :     v8::Local<v8::Object> api_object =
     169           5 :         ConstructTraceableJSApiObject(context, first_field, nullptr);
     170           5 :     CHECK(!api_object.IsEmpty());
     171             :     v8::Local<v8::Object> o =
     172           5 :         v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     173          15 :     o->Set(context, v8_str("link"), api_object).FromJust();
     174             :     g.Reset(isolate, o);
     175           5 :     g.SetWeak(&g, ResurrectingFinalizer, v8::WeakCallbackType::kFinalizer);
     176             :   }
     177           5 :   CcTest::CollectGarbage(i::OLD_SPACE);
     178           5 :   CHECK(tracer.IsRegisteredFromV8(first_field));
     179           5 : }
     180             : 
     181       28342 : TEST(TracingInEphemerons) {
     182             :   // Tests that wrappers that are part of ephemerons are traced.
     183             :   ManualGCScope manual_gc;
     184           5 :   CcTest::InitializeVM();
     185           5 :   v8::Isolate* isolate = CcTest::isolate();
     186           5 :   TestEmbedderHeapTracer tracer(isolate);
     187             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     188          10 :   v8::HandleScope scope(isolate);
     189           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     190             :   v8::Context::Scope context_scope(context);
     191             : 
     192             :   v8::Local<v8::Object> key =
     193           5 :       v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     194             :   void* first_field = reinterpret_cast<void*>(0x8);
     195             :   i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
     196           5 :   Handle<JSWeakMap> weak_map = i_isolate->factory()->NewJSWeakMap();
     197             :   {
     198           5 :     v8::HandleScope inner_scope(isolate);
     199             :     v8::Local<v8::Object> api_object =
     200           5 :         ConstructTraceableJSApiObject(context, first_field, nullptr);
     201           5 :     CHECK(!api_object.IsEmpty());
     202             :     Handle<JSObject> js_key =
     203             :         handle(JSObject::cast(*v8::Utils::OpenHandle(*key)), i_isolate);
     204             :     Handle<JSReceiver> js_api_object = v8::Utils::OpenHandle(*api_object);
     205          10 :     int32_t hash = js_key->GetOrCreateHash(i_isolate)->value();
     206           5 :     JSWeakCollection::Set(weak_map, js_key, js_api_object, hash);
     207             :   }
     208           5 :   CcTest::CollectGarbage(i::OLD_SPACE);
     209           5 :   CHECK(tracer.IsRegisteredFromV8(first_field));
     210           5 : }
     211             : 
     212       28342 : TEST(FinalizeTracingIsNoopWhenNotMarking) {
     213             :   ManualGCScope manual_gc;
     214           5 :   CcTest::InitializeVM();
     215           5 :   v8::Isolate* isolate = CcTest::isolate();
     216             :   Isolate* i_isolate = CcTest::i_isolate();
     217           5 :   TestEmbedderHeapTracer tracer(isolate);
     218             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     219             : 
     220             :   // Finalize a potentially running garbage collection.
     221             :   i_isolate->heap()->CollectGarbage(OLD_SPACE,
     222           5 :                                     GarbageCollectionReason::kTesting);
     223          10 :   CHECK(i_isolate->heap()->incremental_marking()->IsStopped());
     224             : 
     225           5 :   int gc_counter = i_isolate->heap()->gc_count();
     226           5 :   tracer.FinalizeTracing();
     227          10 :   CHECK(i_isolate->heap()->incremental_marking()->IsStopped());
     228           5 :   CHECK_EQ(gc_counter, i_isolate->heap()->gc_count());
     229           5 : }
     230             : 
     231       28342 : TEST(FinalizeTracingWhenMarking) {
     232             :   ManualGCScope manual_gc;
     233           5 :   CcTest::InitializeVM();
     234           5 :   v8::Isolate* isolate = CcTest::isolate();
     235             :   Isolate* i_isolate = CcTest::i_isolate();
     236           5 :   TestEmbedderHeapTracer tracer(isolate);
     237             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     238             : 
     239             :   // Finalize a potentially running garbage collection.
     240             :   i_isolate->heap()->CollectGarbage(OLD_SPACE,
     241           5 :                                     GarbageCollectionReason::kTesting);
     242          10 :   if (i_isolate->heap()->mark_compact_collector()->sweeping_in_progress()) {
     243           5 :     i_isolate->heap()->mark_compact_collector()->EnsureSweepingCompleted();
     244             :   }
     245          10 :   CHECK(i_isolate->heap()->incremental_marking()->IsStopped());
     246             : 
     247             :   i::IncrementalMarking* marking = i_isolate->heap()->incremental_marking();
     248           5 :   marking->Start(i::GarbageCollectionReason::kTesting);
     249             :   // Sweeping is not runing so we should immediately start marking.
     250           5 :   CHECK(marking->IsMarking());
     251           5 :   tracer.FinalizeTracing();
     252           5 :   CHECK(marking->IsStopped());
     253           5 : }
     254             : 
     255       28342 : TEST(GarbageCollectionForTesting) {
     256             :   ManualGCScope manual_gc;
     257           5 :   i::FLAG_expose_gc = true;
     258           5 :   CcTest::InitializeVM();
     259           5 :   v8::Isolate* isolate = CcTest::isolate();
     260             :   Isolate* i_isolate = CcTest::i_isolate();
     261           5 :   TestEmbedderHeapTracer tracer(isolate);
     262             :   TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
     263             : 
     264           5 :   int saved_gc_counter = i_isolate->heap()->gc_count();
     265           5 :   tracer.GarbageCollectionForTesting(EmbedderHeapTracer::kUnknown);
     266          10 :   CHECK_GT(i_isolate->heap()->gc_count(), saved_gc_counter);
     267           5 : }
     268             : 
     269             : }  // namespace heap
     270             : }  // namespace internal
     271       85011 : }  // namespace v8

Generated by: LCOV version 1.10