LCOV - code coverage report
Current view: top level - test/cctest - test-global-handles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 280 281 99.6 %
Date: 2019-04-19 Functions: 58 59 98.3 %

          Line data    Source code
       1             : // Copyright 2013 the V8 project authors. All rights reserved.
       2             : // Redistribution and use in source and binary forms, with or without
       3             : // modification, are permitted provided that the following conditions are
       4             : // met:
       5             : //
       6             : //     * Redistributions of source code must retain the above copyright
       7             : //       notice, this list of conditions and the following disclaimer.
       8             : //     * Redistributions in binary form must reproduce the above
       9             : //       copyright notice, this list of conditions and the following
      10             : //       disclaimer in the documentation and/or other materials provided
      11             : //       with the distribution.
      12             : //     * Neither the name of Google Inc. nor the names of its
      13             : //       contributors may be used to endorse or promote products derived
      14             : //       from this software without specific prior written permission.
      15             : //
      16             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      17             : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      18             : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      19             : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      20             : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      21             : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      22             : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23             : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25             : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      26             : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             : 
      28             : #include "src/api-inl.h"
      29             : #include "src/global-handles.h"
      30             : #include "src/heap/factory.h"
      31             : #include "src/heap/heap-inl.h"
      32             : #include "src/isolate.h"
      33             : #include "src/objects-inl.h"
      34             : #include "test/cctest/cctest.h"
      35             : #include "test/cctest/heap/heap-utils.h"
      36             : 
      37             : namespace v8 {
      38             : namespace internal {
      39             : 
      40             : namespace {
      41             : 
      42          50 : void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
      43             : 
      44          95 : void InvokeMarkSweep() { CcTest::CollectAllGarbage(); }
      45             : 
      46          70 : void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
      47          70 :   info.GetReturnValue().Set(v8_num(0));
      48          70 : }
      49             : 
      50          85 : struct FlagAndPersistent {
      51             :   bool flag;
      52             :   v8::Global<v8::Object> handle;
      53             : };
      54             : 
      55          20 : void ResetHandleAndSetFlag(
      56             :     const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
      57             :   data.GetParameter()->handle.Reset();
      58          20 :   data.GetParameter()->flag = true;
      59          20 : }
      60             : 
      61             : using ConstructFunction = void (*)(v8::Isolate* isolate,
      62             :                                    v8::Local<v8::Context> context,
      63             :                                    FlagAndPersistent* flag_and_persistent);
      64             : 
      65          15 : void ConstructJSObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
      66             :                        FlagAndPersistent* flag_and_persistent) {
      67          30 :   v8::HandleScope handle_scope(isolate);
      68          15 :   v8::Local<v8::Object> object(v8::Object::New(isolate));
      69          15 :   CHECK(!object.IsEmpty());
      70             :   flag_and_persistent->handle.Reset(isolate, object);
      71          15 :   CHECK(!flag_and_persistent->handle.IsEmpty());
      72          15 : }
      73             : 
      74          10 : void ConstructJSObject(v8::Isolate* isolate, v8::Global<v8::Object>* global) {
      75          20 :   v8::HandleScope scope(isolate);
      76          10 :   v8::Local<v8::Object> object(v8::Object::New(isolate));
      77          10 :   CHECK(!object.IsEmpty());
      78          10 :   *global = v8::Global<v8::Object>(isolate, object);
      79          10 :   CHECK(!global->IsEmpty());
      80          10 : }
      81             : 
      82          70 : void ConstructJSApiObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
      83             :                           FlagAndPersistent* flag_and_persistent) {
      84         140 :   v8::HandleScope handle_scope(isolate);
      85             :   v8::Local<v8::FunctionTemplate> fun =
      86          70 :       v8::FunctionTemplate::New(isolate, SimpleCallback);
      87          70 :   v8::Local<v8::Object> object = fun->GetFunction(context)
      88             :                                      .ToLocalChecked()
      89             :                                      ->NewInstance(context)
      90             :                                      .ToLocalChecked();
      91          70 :   CHECK(!object.IsEmpty());
      92             :   flag_and_persistent->handle.Reset(isolate, object);
      93          70 :   CHECK(!flag_and_persistent->handle.IsEmpty());
      94          70 : }
      95             : 
      96             : enum class SurvivalMode { kSurvives, kDies };
      97             : 
      98             : template <typename ModifierFunction, typename GCFunction>
      99          55 : void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function,
     100             :                     ModifierFunction modifier_function, GCFunction gc_function,
     101             :                     SurvivalMode survives) {
     102         110 :   v8::HandleScope scope(isolate);
     103          55 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     104             :   v8::Context::Scope context_scope(context);
     105             : 
     106             :   FlagAndPersistent fp;
     107          55 :   construct_function(isolate, context, &fp);
     108          55 :   CHECK(heap::InYoungGeneration(isolate, fp.handle));
     109             :   fp.handle.SetWeak(&fp, &ResetHandleAndSetFlag,
     110             :                     v8::WeakCallbackType::kParameter);
     111          55 :   fp.flag = false;
     112          25 :   modifier_function(&fp);
     113             :   gc_function();
     114          55 :   CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !fp.flag);
     115          55 :   CHECK_IMPLIES(survives == SurvivalMode::kDies, fp.flag);
     116          55 : }
     117             : 
     118           5 : void ResurrectingFinalizer(
     119             :     const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
     120             :   data.GetParameter()->ClearWeak();
     121           5 : }
     122             : 
     123           5 : void ResettingFinalizer(
     124             :     const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
     125             :   data.GetParameter()->Reset();
     126           5 : }
     127             : 
     128           0 : void EmptyWeakCallback(const v8::WeakCallbackInfo<void>& data) {}
     129             : 
     130           5 : void ResurrectingFinalizerSettingProperty(
     131             :     const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
     132             :   data.GetParameter()->ClearWeak();
     133             :   v8::Local<v8::Object> o =
     134             :       v8::Local<v8::Object>::New(data.GetIsolate(), *data.GetParameter());
     135          10 :   o->Set(data.GetIsolate()->GetCurrentContext(), v8_str("finalizer"),
     136          20 :          v8_str("was here"))
     137             :       .FromJust();
     138           5 : }
     139             : 
     140             : }  // namespace
     141             : 
     142       26661 : TEST(EternalHandles) {
     143           5 :   CcTest::InitializeVM();
     144             :   Isolate* isolate = CcTest::i_isolate();
     145             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     146             :   EternalHandles* eternal_handles = isolate->eternal_handles();
     147             : 
     148             :   // Create a number of handles that will not be on a block boundary
     149             :   const int kArrayLength = 2048-1;
     150             :   int indices[kArrayLength];
     151       20475 :   v8::Eternal<v8::Value> eternals[kArrayLength];
     152             : 
     153           5 :   CHECK_EQ(0, eternal_handles->handles_count());
     154       20475 :   for (int i = 0; i < kArrayLength; i++) {
     155       10235 :     indices[i] = -1;
     156             :     HandleScope scope(isolate);
     157       10235 :     v8::Local<v8::Object> object = v8::Object::New(v8_isolate);
     158       20470 :     object->Set(v8_isolate->GetCurrentContext(), i,
     159       30705 :                 v8::Integer::New(v8_isolate, i))
     160             :         .FromJust();
     161             :     // Create with internal api
     162       30705 :     eternal_handles->Create(
     163       10235 :         isolate, *v8::Utils::OpenHandle(*object), &indices[i]);
     164             :     // Create with external api
     165       10235 :     CHECK(eternals[i].IsEmpty());
     166             :     eternals[i].Set(v8_isolate, object);
     167       10235 :     CHECK(!eternals[i].IsEmpty());
     168             :   }
     169             : 
     170           5 :   CcTest::CollectAllAvailableGarbage();
     171             : 
     172       20475 :   for (int i = 0; i < kArrayLength; i++) {
     173       51175 :     for (int j = 0; j < 2; j++) {
     174             :       HandleScope scope(isolate);
     175             :       v8::Local<v8::Value> local;
     176       20470 :       if (j == 0) {
     177             :         // Test internal api
     178       10235 :         local = v8::Utils::ToLocal(eternal_handles->Get(indices[i]));
     179             :       } else {
     180             :         // Test external api
     181             :         local = eternals[i].Get(v8_isolate);
     182             :       }
     183             :       v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(local);
     184             :       v8::Local<v8::Value> value =
     185       20470 :           object->Get(v8_isolate->GetCurrentContext(), i).ToLocalChecked();
     186       20470 :       CHECK(value->IsInt32());
     187       40940 :       CHECK_EQ(i,
     188             :                value->Int32Value(v8_isolate->GetCurrentContext()).FromJust());
     189             :     }
     190             :   }
     191             : 
     192           5 :   CHECK_EQ(2 * kArrayLength, eternal_handles->handles_count());
     193             : 
     194             :   // Create an eternal via the constructor
     195             :   {
     196             :     HandleScope scope(isolate);
     197           5 :     v8::Local<v8::Object> object = v8::Object::New(v8_isolate);
     198             :     v8::Eternal<v8::Object> eternal(v8_isolate, object);
     199           5 :     CHECK(!eternal.IsEmpty());
     200           5 :     CHECK(object == eternal.Get(v8_isolate));
     201             :   }
     202             : 
     203           5 :   CHECK_EQ(2 * kArrayLength + 1, eternal_handles->handles_count());
     204           5 : }
     205             : 
     206             : 
     207       26661 : TEST(PersistentBaseGetLocal) {
     208           5 :   CcTest::InitializeVM();
     209           5 :   v8::Isolate* isolate = CcTest::isolate();
     210             : 
     211          10 :   v8::HandleScope scope(isolate);
     212           5 :   v8::Local<v8::Object> o = v8::Object::New(isolate);
     213           5 :   CHECK(!o.IsEmpty());
     214             :   v8::Persistent<v8::Object> p(isolate, o);
     215           5 :   CHECK(o == p.Get(isolate));
     216           5 :   CHECK(v8::Local<v8::Object>::New(isolate, p) == p.Get(isolate));
     217             : 
     218             :   v8::Global<v8::Object> g(isolate, o);
     219           5 :   CHECK(o == g.Get(isolate));
     220           5 :   CHECK(v8::Local<v8::Object>::New(isolate, g) == g.Get(isolate));
     221           5 : }
     222             : 
     223       26661 : TEST(WeakPersistentSmi) {
     224           5 :   CcTest::InitializeVM();
     225           5 :   v8::Isolate* isolate = CcTest::isolate();
     226             : 
     227          10 :   v8::HandleScope scope(isolate);
     228           5 :   v8::Local<v8::Number> n = v8::Number::New(isolate, 0);
     229             :   v8::Global<v8::Number> g(isolate, n);
     230             : 
     231             :   // Should not crash.
     232             :   g.SetWeak<void>(nullptr, &EmptyWeakCallback,
     233             :                   v8::WeakCallbackType::kParameter);
     234           5 : }
     235             : 
     236       26661 : TEST(FinalizerWeakness) {
     237           5 :   CcTest::InitializeVM();
     238           5 :   v8::Isolate* isolate = CcTest::isolate();
     239             : 
     240             :   v8::Global<v8::Object> g;
     241             :   int identity;
     242             : 
     243             :   {
     244          10 :     v8::HandleScope scope(isolate);
     245           5 :     v8::Local<v8::Object> o = v8::Object::New(isolate);
     246           5 :     identity = o->GetIdentityHash();
     247             :     g.Reset(isolate, o);
     248             :     g.SetWeak(&g, &ResurrectingFinalizerSettingProperty,
     249             :               v8::WeakCallbackType::kFinalizer);
     250             :   }
     251             : 
     252           5 :   CcTest::CollectAllAvailableGarbage();
     253             : 
     254           5 :   CHECK(!g.IsEmpty());
     255          10 :   v8::HandleScope scope(isolate);
     256             :   v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, g);
     257           5 :   CHECK_EQ(identity, o->GetIdentityHash());
     258          15 :   CHECK(o->Has(isolate->GetCurrentContext(), v8_str("finalizer")).FromJust());
     259           5 : }
     260             : 
     261       26661 : TEST(PhatomHandlesWithoutCallbacks) {
     262           5 :   CcTest::InitializeVM();
     263           5 :   v8::Isolate* isolate = CcTest::isolate();
     264             : 
     265             :   v8::Global<v8::Object> g1, g2;
     266             :   {
     267          10 :     v8::HandleScope scope(isolate);
     268          10 :     g1.Reset(isolate, v8::Object::New(isolate));
     269             :     g1.SetWeak();
     270          10 :     g2.Reset(isolate, v8::Object::New(isolate));
     271             :     g2.SetWeak();
     272             :   }
     273             : 
     274           5 :   CHECK_EQ(0u, isolate->NumberOfPhantomHandleResetsSinceLastCall());
     275           5 :   CcTest::CollectAllAvailableGarbage();
     276           5 :   CHECK_EQ(2u, isolate->NumberOfPhantomHandleResetsSinceLastCall());
     277           5 :   CHECK_EQ(0u, isolate->NumberOfPhantomHandleResetsSinceLastCall());
     278           5 : }
     279             : 
     280       26661 : TEST(WeakHandleToUnmodifiedJSObjectSurvivesScavenge) {
     281           5 :   CcTest::InitializeVM();
     282           5 :   WeakHandleTest(
     283             :       CcTest::isolate(), &ConstructJSObject, [](FlagAndPersistent* fp) {},
     284           5 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     285           5 : }
     286             : 
     287       26661 : TEST(WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact) {
     288           5 :   CcTest::InitializeVM();
     289           5 :   WeakHandleTest(
     290             :       CcTest::isolate(), &ConstructJSObject, [](FlagAndPersistent* fp) {},
     291           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kDies);
     292           5 : }
     293             : 
     294       26661 : TEST(WeakHandleToUnmodifiedJSObjectSurvivesMarkCompactWhenInHandle) {
     295           5 :   CcTest::InitializeVM();
     296           5 :   WeakHandleTest(
     297             :       CcTest::isolate(), &ConstructJSObject,
     298           5 :       [](FlagAndPersistent* fp) {
     299             :         v8::Local<v8::Object> handle =
     300           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     301             :         USE(handle);
     302           5 :       },
     303           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
     304           5 : }
     305             : 
     306       26661 : TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnScavenge) {
     307           5 :   CcTest::InitializeVM();
     308           5 :   WeakHandleTest(
     309             :       CcTest::isolate(), &ConstructJSApiObject, [](FlagAndPersistent* fp) {},
     310           5 :       []() { InvokeScavenge(); }, SurvivalMode::kDies);
     311           5 : }
     312             : 
     313       26661 : TEST(WeakHandleToJSApiObjectWithIdentityHashSurvivesScavenge) {
     314           5 :   CcTest::InitializeVM();
     315             :   Isolate* i_isolate = CcTest::i_isolate();
     316             :   HandleScope scope(i_isolate);
     317           5 :   Handle<JSWeakMap> weakmap = i_isolate->factory()->NewJSWeakMap();
     318             : 
     319           5 :   WeakHandleTest(
     320             :       CcTest::isolate(), &ConstructJSApiObject,
     321          20 :       [&weakmap, i_isolate](FlagAndPersistent* fp) {
     322          10 :         v8::HandleScope scope(CcTest::isolate());
     323             :         Handle<JSReceiver> key =
     324           5 :             Utils::OpenHandle(*fp->handle.Get(CcTest::isolate()));
     325             :         Handle<Smi> smi(Smi::FromInt(23), i_isolate);
     326          10 :         int32_t hash = key->GetOrCreateHash(i_isolate)->value();
     327           5 :         JSWeakCollection::Set(weakmap, key, smi, hash);
     328           5 :       },
     329          10 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     330           5 : }
     331             : 
     332       26661 : TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesScavengeWhenInHandle) {
     333           5 :   CcTest::InitializeVM();
     334           5 :   WeakHandleTest(
     335             :       CcTest::isolate(), &ConstructJSApiObject,
     336           5 :       [](FlagAndPersistent* fp) {
     337             :         v8::Local<v8::Object> handle =
     338           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     339             :         USE(handle);
     340           5 :       },
     341           5 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     342           5 : }
     343             : 
     344       26661 : TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnMarkCompact) {
     345           5 :   CcTest::InitializeVM();
     346           5 :   WeakHandleTest(
     347             :       CcTest::isolate(), &ConstructJSApiObject, [](FlagAndPersistent* fp) {},
     348           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kDies);
     349           5 : }
     350             : 
     351       26661 : TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) {
     352           5 :   CcTest::InitializeVM();
     353           5 :   WeakHandleTest(
     354             :       CcTest::isolate(), &ConstructJSApiObject,
     355           5 :       [](FlagAndPersistent* fp) {
     356             :         v8::Local<v8::Object> handle =
     357           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     358             :         USE(handle);
     359           5 :       },
     360           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
     361           5 : }
     362             : 
     363       26661 : TEST(WeakHandleToActiveUnmodifiedJSApiObjectSurvivesScavenge) {
     364           5 :   CcTest::InitializeVM();
     365           5 :   WeakHandleTest(
     366             :       CcTest::isolate(), &ConstructJSApiObject,
     367             :       [](FlagAndPersistent* fp) {
     368             : #if __clang__
     369             : #pragma clang diagnostic push
     370             : #pragma clang diagnostic ignored "-Wdeprecated"
     371             : #endif
     372             :         fp->handle.MarkActive();
     373             : #if __clang__
     374             : #pragma clang diagnostic pop
     375             : #endif
     376             :       },
     377           5 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     378           5 : }
     379             : 
     380       26661 : TEST(WeakHandleToActiveUnmodifiedJSApiObjectDiesOnMarkCompact) {
     381           5 :   CcTest::InitializeVM();
     382           5 :   WeakHandleTest(
     383             :       CcTest::isolate(), &ConstructJSApiObject,
     384             :       [](FlagAndPersistent* fp) {
     385             : #if __clang__
     386             : #pragma clang diagnostic push
     387             : #pragma clang diagnostic ignored "-Wdeprecated"
     388             : #endif
     389             :         fp->handle.MarkActive();
     390             : #if __clang__
     391             : #pragma clang diagnostic pop
     392             : #endif
     393             :       },
     394           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kDies);
     395           5 : }
     396             : 
     397       26661 : TEST(WeakHandleToActiveUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) {
     398           5 :   CcTest::InitializeVM();
     399           5 :   WeakHandleTest(
     400             :       CcTest::isolate(), &ConstructJSApiObject,
     401           5 :       [](FlagAndPersistent* fp) {
     402             : #if __clang__
     403             : #pragma clang diagnostic push
     404             : #pragma clang diagnostic ignored "-Wdeprecated"
     405             : #endif
     406             :         fp->handle.MarkActive();
     407             : #if __clang__
     408             : #pragma clang diagnostic pop
     409             : #endif
     410             :         v8::Local<v8::Object> handle =
     411           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     412             :         USE(handle);
     413           5 :       },
     414           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
     415           5 : }
     416             : 
     417       26661 : TEST(FinalizerOnUnmodifiedJSApiObjectDoesNotCrash) {
     418             :   // See crbug.com/v8/8586.
     419           5 :   CcTest::InitializeVM();
     420           5 :   v8::Isolate* isolate = CcTest::isolate();
     421          10 :   v8::HandleScope scope(isolate);
     422           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     423             :   v8::Context::Scope context_scope(context);
     424             : 
     425             :   FlagAndPersistent fp;
     426             :   // Could use a regular object and MarkIndependent too.
     427           5 :   ConstructJSApiObject(isolate, context, &fp);
     428             :   fp.handle.SetWeak(&fp, &ResetHandleAndSetFlag,
     429             :                     v8::WeakCallbackType::kFinalizer);
     430           5 :   fp.flag = false;
     431             :   {
     432          10 :     v8::HandleScope scope(isolate);
     433             :     v8::Local<v8::Object> tmp = v8::Local<v8::Object>::New(isolate, fp.handle);
     434             :     USE(tmp);
     435             :     InvokeScavenge();
     436             :   }
     437           5 : }
     438             : 
     439             : namespace {
     440             : 
     441          10 : void ConstructFinalizerPointingPhantomHandle(
     442             :     v8::Isolate* isolate, v8::Global<v8::Object>* g1,
     443             :     v8::Global<v8::Object>* g2,
     444             :     typename v8::WeakCallbackInfo<v8::Global<v8::Object>>::Callback
     445             :         finalizer_for_g1) {
     446          20 :   v8::HandleScope scope(isolate);
     447             :   v8::Local<v8::Object> o1 =
     448          10 :       v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     449             :   v8::Local<v8::Object> o2 =
     450          10 :       v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     451          30 :   o1->Set(isolate->GetCurrentContext(), v8_str("link"), o2).FromJust();
     452             :   g1->Reset(isolate, o1);
     453             :   g2->Reset(isolate, o2);
     454             :   // g1 will be finalized but resurrected.
     455             :   g1->SetWeak(g1, finalizer_for_g1, v8::WeakCallbackType::kFinalizer);
     456             :   // g2 will be a phantom handle that is dependent on the finalizer handle
     457             :   // g1 as it is in its subgraph.
     458             :   g2->SetWeak();
     459          10 : }
     460             : 
     461             : }  // namespace
     462             : 
     463       26661 : TEST(FinalizerResurrectsAndKeepsPhantomAliveOnMarkCompact) {
     464             :   // See crbug.com/772299.
     465           5 :   CcTest::InitializeVM();
     466             :   v8::Global<v8::Object> g1, g2;
     467           5 :   ConstructFinalizerPointingPhantomHandle(CcTest::isolate(), &g1, &g2,
     468           5 :                                           ResurrectingFinalizer);
     469             :   InvokeMarkSweep();
     470             :   // Both, g1 and g2, should stay alive as the finalizer resurrects the root
     471             :   // object that transitively keeps the other one alive.
     472           5 :   CHECK(!g1.IsEmpty());
     473           5 :   CHECK(!g2.IsEmpty());
     474             :   InvokeMarkSweep();
     475             :   // The finalizer handle is now strong, so it should keep the objects alive.
     476           5 :   CHECK(!g1.IsEmpty());
     477           5 :   CHECK(!g2.IsEmpty());
     478           5 : }
     479             : 
     480       26661 : TEST(FinalizerDiesAndKeepsPhantomAliveOnMarkCompact) {
     481           5 :   CcTest::InitializeVM();
     482             :   v8::Global<v8::Object> g1, g2;
     483           5 :   ConstructFinalizerPointingPhantomHandle(CcTest::isolate(), &g1, &g2,
     484           5 :                                           ResettingFinalizer);
     485             :   InvokeMarkSweep();
     486             :   // Finalizer (g1) dies but the phantom handle (g2) is kept alive for one
     487             :   // more round as the underlying object only dies on the next GC.
     488           5 :   CHECK(g1.IsEmpty());
     489           5 :   CHECK(!g2.IsEmpty());
     490             :   InvokeMarkSweep();
     491             :   // Phantom handle dies after one more round.
     492           5 :   CHECK(g1.IsEmpty());
     493           5 :   CHECK(g2.IsEmpty());
     494           5 : }
     495             : 
     496             : namespace {
     497             : 
     498          10 : void ForceScavenge2(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     499          10 :   data.GetParameter()->flag = true;
     500             :   InvokeScavenge();
     501          10 : }
     502             : 
     503          10 : void ForceScavenge1(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     504             :   data.GetParameter()->handle.Reset();
     505             :   data.SetSecondPassCallback(ForceScavenge2);
     506          10 : }
     507             : 
     508          10 : void ForceMarkSweep2(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     509          10 :   data.GetParameter()->flag = true;
     510             :   InvokeMarkSweep();
     511          10 : }
     512             : 
     513          10 : void ForceMarkSweep1(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     514             :   data.GetParameter()->handle.Reset();
     515             :   data.SetSecondPassCallback(ForceMarkSweep2);
     516          10 : }
     517             : 
     518             : }  // namespace
     519             : 
     520       26661 : TEST(GCFromWeakCallbacks) {
     521           5 :   v8::Isolate* isolate = CcTest::isolate();
     522          10 :   v8::Locker locker(CcTest::isolate());
     523          10 :   v8::HandleScope scope(isolate);
     524           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     525             :   v8::Context::Scope context_scope(context);
     526             : 
     527             :   static const int kNumberOfGCTypes = 2;
     528             :   typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
     529             :   Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
     530           5 :                                                     &ForceMarkSweep1};
     531             : 
     532             :   typedef void (*GCInvoker)();
     533           5 :   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
     534             : 
     535          25 :   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
     536          50 :     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
     537             :       FlagAndPersistent fp;
     538          20 :       ConstructJSApiObject(isolate, context, &fp);
     539          20 :       CHECK(heap::InYoungGeneration(isolate, fp.handle));
     540          20 :       fp.flag = false;
     541          20 :       fp.handle.SetWeak(&fp, gc_forcing_callback[inner_gc],
     542             :                         v8::WeakCallbackType::kParameter);
     543          20 :       invoke_gc[outer_gc]();
     544          20 :       EmptyMessageQueues(isolate);
     545          20 :       CHECK(fp.flag);
     546             :     }
     547             :   }
     548           5 : }
     549             : 
     550             : namespace {
     551             : 
     552           5 : void SecondPassCallback(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     553           5 :   data.GetParameter()->flag = true;
     554           5 : }
     555             : 
     556           5 : void FirstPassCallback(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     557             :   data.GetParameter()->handle.Reset();
     558             :   data.SetSecondPassCallback(SecondPassCallback);
     559           5 : }
     560             : 
     561             : }  // namespace
     562             : 
     563       26661 : TEST(SecondPassPhantomCallbacks) {
     564           5 :   v8::Isolate* isolate = CcTest::isolate();
     565          10 :   v8::Locker locker(CcTest::isolate());
     566          10 :   v8::HandleScope scope(isolate);
     567           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     568             :   v8::Context::Scope context_scope(context);
     569             :   FlagAndPersistent fp;
     570           5 :   ConstructJSApiObject(isolate, context, &fp);
     571           5 :   fp.flag = false;
     572             :   fp.handle.SetWeak(&fp, FirstPassCallback, v8::WeakCallbackType::kParameter);
     573           5 :   CHECK(!fp.flag);
     574             :   InvokeMarkSweep();
     575             :   InvokeMarkSweep();
     576           5 :   CHECK(fp.flag);
     577           5 : }
     578             : 
     579       26661 : TEST(MoveStrongGlobal) {
     580           5 :   CcTest::InitializeVM();
     581           5 :   v8::Isolate* isolate = CcTest::isolate();
     582          10 :   v8::HandleScope scope(isolate);
     583             : 
     584           5 :   v8::Global<v8::Object>* global = new Global<v8::Object>();
     585           5 :   ConstructJSObject(isolate, global);
     586             :   InvokeMarkSweep();
     587             :   v8::Global<v8::Object> global2(std::move(*global));
     588          10 :   delete global;
     589             :   InvokeMarkSweep();
     590           5 : }
     591             : 
     592       26661 : TEST(MoveWeakGlobal) {
     593           5 :   CcTest::InitializeVM();
     594           5 :   v8::Isolate* isolate = CcTest::isolate();
     595          10 :   v8::HandleScope scope(isolate);
     596             : 
     597           5 :   v8::Global<v8::Object>* global = new Global<v8::Object>();
     598           5 :   ConstructJSObject(isolate, global);
     599             :   InvokeMarkSweep();
     600             :   global->SetWeak();
     601             :   v8::Global<v8::Object> global2(std::move(*global));
     602          10 :   delete global;
     603             :   InvokeMarkSweep();
     604           5 : }
     605             : 
     606             : }  // namespace internal
     607       79968 : }  // namespace v8

Generated by: LCOV version 1.10