LCOV - code coverage report
Current view: top level - test/cctest - test-global-handles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 270 271 99.6 %
Date: 2019-02-19 Functions: 55 56 98.2 %

          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          45 : void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
      43             : 
      44          95 : void InvokeMarkSweep() { CcTest::CollectAllGarbage(); }
      45             : 
      46         130 : void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
      47          65 :   info.GetReturnValue().Set(v8_num(0));
      48          65 : }
      49             : 
      50             : struct FlagAndPersistent {
      51             :   bool flag;
      52             :   v8::Global<v8::Object> handle;
      53             : };
      54             : 
      55          20 : void ResetHandleAndSetFlag(
      56          40 :     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          15 :   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          10 :   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          65 : void ConstructJSApiObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
      83             :                           FlagAndPersistent* flag_and_persistent) {
      84          65 :   v8::HandleScope handle_scope(isolate);
      85             :   v8::Local<v8::FunctionTemplate> fun =
      86          65 :       v8::FunctionTemplate::New(isolate, SimpleCallback);
      87             :   v8::Local<v8::Object> object = fun->GetFunction(context)
      88          65 :                                      .ToLocalChecked()
      89             :                                      ->NewInstance(context)
      90             :                                      .ToLocalChecked();
      91          65 :   CHECK(!object.IsEmpty());
      92             :   flag_and_persistent->handle.Reset(isolate, object);
      93          65 :   CHECK(!flag_and_persistent->handle.IsEmpty());
      94          65 : }
      95             : 
      96             : enum class SurvivalMode { kSurvives, kDies };
      97             : 
      98             : template <typename ModifierFunction, typename GCFunction>
      99          50 : void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function,
     100             :                     ModifierFunction modifier_function, GCFunction gc_function,
     101             :                     SurvivalMode survives) {
     102          50 :   v8::HandleScope scope(isolate);
     103          50 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     104             :   v8::Context::Scope context_scope(context);
     105             : 
     106             :   FlagAndPersistent fp;
     107          50 :   construct_function(isolate, context, &fp);
     108          50 :   CHECK(heap::InYoungGeneration(isolate, fp.handle));
     109             :   fp.handle.SetWeak(&fp, &ResetHandleAndSetFlag,
     110             :                     v8::WeakCallbackType::kParameter);
     111          50 :   fp.flag = false;
     112          20 :   modifier_function(&fp);
     113             :   gc_function();
     114          50 :   CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !fp.flag);
     115         100 :   CHECK_IMPLIES(survives == SurvivalMode::kDies, fp.flag);
     116          50 : }
     117             : 
     118           5 : void ResurrectingFinalizer(
     119           5 :     const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
     120             :   data.GetParameter()->ClearWeak();
     121           5 : }
     122             : 
     123           5 : void ResettingFinalizer(
     124           5 :     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          15 :     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             :   o->Set(data.GetIsolate()->GetCurrentContext(), v8_str("finalizer"),
     136          20 :          v8_str("was here"))
     137          10 :       .FromJust();
     138           5 : }
     139             : 
     140             : }  // namespace
     141             : 
     142       25880 : TEST(EternalHandles) {
     143           5 :   CcTest::InitializeVM();
     144           5 :   Isolate* isolate = CcTest::i_isolate();
     145             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     146          15 :   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       10240 :   v8::Eternal<v8::Value> eternals[kArrayLength];
     152             : 
     153           5 :   CHECK_EQ(0, eternal_handles->handles_count());
     154       10235 :   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             :     object->Set(v8_isolate->GetCurrentContext(), i,
     159       30705 :                 v8::Integer::New(v8_isolate, i))
     160       20470 :         .FromJust();
     161             :     // Create with internal api
     162             :     eternal_handles->Create(
     163       20470 :         isolate, *v8::Utils::OpenHandle(*object), &indices[i]);
     164             :     // Create with external api
     165       20470 :     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       10240 :   for (int i = 0; i < kArrayLength; i++) {
     173       20470 :     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       10235 :         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       25880 : TEST(PersistentBaseGetLocal) {
     208           5 :   CcTest::InitializeVM();
     209           5 :   v8::Isolate* isolate = CcTest::isolate();
     210             : 
     211           5 :   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          10 :   CHECK(v8::Local<v8::Object>::New(isolate, g) == g.Get(isolate));
     221           5 : }
     222             : 
     223       25880 : TEST(WeakPersistentSmi) {
     224           5 :   CcTest::InitializeVM();
     225           5 :   v8::Isolate* isolate = CcTest::isolate();
     226             : 
     227           5 :   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           5 :                   v8::WeakCallbackType::kParameter);
     234           5 : }
     235             : 
     236       25880 : 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           5 :     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           5 :               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       25880 : TEST(PhatomHandlesWithoutCallbacks) {
     262           5 :   CcTest::InitializeVM();
     263           5 :   v8::Isolate* isolate = CcTest::isolate();
     264             : 
     265             :   v8::Global<v8::Object> g1, g2;
     266             :   {
     267           5 :     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           5 :     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       25880 : TEST(WeakHandleToUnmodifiedJSObjectSurvivesScavenge) {
     281           5 :   CcTest::InitializeVM();
     282             :   WeakHandleTest(
     283             :       CcTest::isolate(), &ConstructJSObject, [](FlagAndPersistent* fp) {},
     284           5 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     285           5 : }
     286             : 
     287       25880 : TEST(WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact) {
     288           5 :   CcTest::InitializeVM();
     289             :   WeakHandleTest(
     290             :       CcTest::isolate(), &ConstructJSObject, [](FlagAndPersistent* fp) {},
     291           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kDies);
     292           5 : }
     293             : 
     294       25880 : TEST(WeakHandleToUnmodifiedJSObjectSurvivesMarkCompactWhenInHandle) {
     295           5 :   CcTest::InitializeVM();
     296             :   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       25880 : TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnScavenge) {
     307           5 :   CcTest::InitializeVM();
     308             :   WeakHandleTest(
     309             :       CcTest::isolate(), &ConstructJSApiObject, [](FlagAndPersistent* fp) {},
     310           5 :       []() { InvokeScavenge(); }, SurvivalMode::kDies);
     311           5 : }
     312             : 
     313       25880 : TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesScavengeWhenInHandle) {
     314           5 :   CcTest::InitializeVM();
     315             :   WeakHandleTest(
     316             :       CcTest::isolate(), &ConstructJSApiObject,
     317           5 :       [](FlagAndPersistent* fp) {
     318             :         v8::Local<v8::Object> handle =
     319           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     320             :         USE(handle);
     321           5 :       },
     322           5 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     323           5 : }
     324             : 
     325       25880 : TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnMarkCompact) {
     326           5 :   CcTest::InitializeVM();
     327             :   WeakHandleTest(
     328             :       CcTest::isolate(), &ConstructJSApiObject, [](FlagAndPersistent* fp) {},
     329           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kDies);
     330           5 : }
     331             : 
     332       25880 : TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) {
     333           5 :   CcTest::InitializeVM();
     334             :   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 :       []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
     342           5 : }
     343             : 
     344       25880 : TEST(WeakHandleToActiveUnmodifiedJSApiObjectSurvivesScavenge) {
     345           5 :   CcTest::InitializeVM();
     346             :   WeakHandleTest(
     347             :       CcTest::isolate(), &ConstructJSApiObject,
     348             :       [](FlagAndPersistent* fp) {
     349             : #if __clang__
     350             : #pragma clang diagnostic push
     351             : #pragma clang diagnostic ignored "-Wdeprecated"
     352             : #endif
     353             :         fp->handle.MarkActive();
     354             : #if __clang__
     355             : #pragma clang diagnostic pop
     356             : #endif
     357             :       },
     358           5 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     359           5 : }
     360             : 
     361       25880 : TEST(WeakHandleToActiveUnmodifiedJSApiObjectDiesOnMarkCompact) {
     362           5 :   CcTest::InitializeVM();
     363             :   WeakHandleTest(
     364             :       CcTest::isolate(), &ConstructJSApiObject,
     365             :       [](FlagAndPersistent* fp) {
     366             : #if __clang__
     367             : #pragma clang diagnostic push
     368             : #pragma clang diagnostic ignored "-Wdeprecated"
     369             : #endif
     370             :         fp->handle.MarkActive();
     371             : #if __clang__
     372             : #pragma clang diagnostic pop
     373             : #endif
     374             :       },
     375           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kDies);
     376           5 : }
     377             : 
     378       25880 : TEST(WeakHandleToActiveUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) {
     379           5 :   CcTest::InitializeVM();
     380             :   WeakHandleTest(
     381             :       CcTest::isolate(), &ConstructJSApiObject,
     382           5 :       [](FlagAndPersistent* fp) {
     383             : #if __clang__
     384             : #pragma clang diagnostic push
     385             : #pragma clang diagnostic ignored "-Wdeprecated"
     386             : #endif
     387             :         fp->handle.MarkActive();
     388             : #if __clang__
     389             : #pragma clang diagnostic pop
     390             : #endif
     391             :         v8::Local<v8::Object> handle =
     392           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     393             :         USE(handle);
     394           5 :       },
     395           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
     396           5 : }
     397             : 
     398       25880 : TEST(FinalizerOnUnmodifiedJSApiObjectDoesNotCrash) {
     399             :   // See crbug.com/v8/8586.
     400           5 :   CcTest::InitializeVM();
     401           5 :   v8::Isolate* isolate = CcTest::isolate();
     402           5 :   v8::HandleScope scope(isolate);
     403           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     404             :   v8::Context::Scope context_scope(context);
     405             : 
     406             :   FlagAndPersistent fp;
     407             :   // Could use a regular object and MarkIndependent too.
     408           5 :   ConstructJSApiObject(isolate, context, &fp);
     409             :   fp.handle.SetWeak(&fp, &ResetHandleAndSetFlag,
     410             :                     v8::WeakCallbackType::kFinalizer);
     411           5 :   fp.flag = false;
     412             :   {
     413           5 :     v8::HandleScope scope(isolate);
     414             :     v8::Local<v8::Object> tmp = v8::Local<v8::Object>::New(isolate, fp.handle);
     415             :     USE(tmp);
     416           5 :     InvokeScavenge();
     417           5 :   }
     418           5 : }
     419             : 
     420             : namespace {
     421             : 
     422          10 : void ConstructFinalizerPointingPhantomHandle(
     423             :     v8::Isolate* isolate, v8::Global<v8::Object>* g1,
     424             :     v8::Global<v8::Object>* g2,
     425             :     typename v8::WeakCallbackInfo<v8::Global<v8::Object>>::Callback
     426             :         finalizer_for_g1) {
     427          10 :   v8::HandleScope scope(isolate);
     428             :   v8::Local<v8::Object> o1 =
     429          10 :       v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     430             :   v8::Local<v8::Object> o2 =
     431          10 :       v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     432          30 :   o1->Set(isolate->GetCurrentContext(), v8_str("link"), o2).FromJust();
     433             :   g1->Reset(isolate, o1);
     434             :   g2->Reset(isolate, o2);
     435             :   // g1 will be finalized but resurrected.
     436             :   g1->SetWeak(g1, finalizer_for_g1, v8::WeakCallbackType::kFinalizer);
     437             :   // g2 will be a phantom handle that is dependent on the finalizer handle
     438             :   // g1 as it is in its subgraph.
     439          10 :   g2->SetWeak();
     440          10 : }
     441             : 
     442             : }  // namespace
     443             : 
     444       25880 : TEST(FinalizerResurrectsAndKeepsPhantomAliveOnMarkCompact) {
     445             :   // See crbug.com/772299.
     446           5 :   CcTest::InitializeVM();
     447             :   v8::Global<v8::Object> g1, g2;
     448             :   ConstructFinalizerPointingPhantomHandle(CcTest::isolate(), &g1, &g2,
     449           5 :                                           ResurrectingFinalizer);
     450             :   InvokeMarkSweep();
     451             :   // Both, g1 and g2, should stay alive as the finalizer resurrects the root
     452             :   // object that transitively keeps the other one alive.
     453           5 :   CHECK(!g1.IsEmpty());
     454           5 :   CHECK(!g2.IsEmpty());
     455             :   InvokeMarkSweep();
     456             :   // The finalizer handle is now strong, so it should keep the objects alive.
     457           5 :   CHECK(!g1.IsEmpty());
     458           5 :   CHECK(!g2.IsEmpty());
     459           5 : }
     460             : 
     461       25880 : TEST(FinalizerDiesAndKeepsPhantomAliveOnMarkCompact) {
     462           5 :   CcTest::InitializeVM();
     463             :   v8::Global<v8::Object> g1, g2;
     464             :   ConstructFinalizerPointingPhantomHandle(CcTest::isolate(), &g1, &g2,
     465           5 :                                           ResettingFinalizer);
     466             :   InvokeMarkSweep();
     467             :   // Finalizer (g1) dies but the phantom handle (g2) is kept alive for one
     468             :   // more round as the underlying object only dies on the next GC.
     469           5 :   CHECK(g1.IsEmpty());
     470           5 :   CHECK(!g2.IsEmpty());
     471             :   InvokeMarkSweep();
     472             :   // Phantom handle dies after one more round.
     473           5 :   CHECK(g1.IsEmpty());
     474           5 :   CHECK(g2.IsEmpty());
     475           5 : }
     476             : 
     477             : namespace {
     478             : 
     479          10 : void ForceScavenge2(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     480          10 :   data.GetParameter()->flag = true;
     481             :   InvokeScavenge();
     482          10 : }
     483             : 
     484          20 : void ForceScavenge1(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     485             :   data.GetParameter()->handle.Reset();
     486             :   data.SetSecondPassCallback(ForceScavenge2);
     487          10 : }
     488             : 
     489          10 : void ForceMarkSweep2(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     490          10 :   data.GetParameter()->flag = true;
     491             :   InvokeMarkSweep();
     492          10 : }
     493             : 
     494          20 : void ForceMarkSweep1(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     495             :   data.GetParameter()->handle.Reset();
     496             :   data.SetSecondPassCallback(ForceMarkSweep2);
     497          10 : }
     498             : 
     499             : }  // namespace
     500             : 
     501       25880 : TEST(GCFromWeakCallbacks) {
     502           5 :   v8::Isolate* isolate = CcTest::isolate();
     503           5 :   v8::Locker locker(CcTest::isolate());
     504          10 :   v8::HandleScope scope(isolate);
     505           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     506             :   v8::Context::Scope context_scope(context);
     507             : 
     508             :   static const int kNumberOfGCTypes = 2;
     509             :   typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
     510             :   Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
     511           5 :                                                     &ForceMarkSweep1};
     512             : 
     513             :   typedef void (*GCInvoker)();
     514           5 :   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
     515             : 
     516          15 :   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
     517          20 :     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
     518             :       FlagAndPersistent fp;
     519          20 :       ConstructJSApiObject(isolate, context, &fp);
     520          20 :       CHECK(heap::InYoungGeneration(isolate, fp.handle));
     521          20 :       fp.flag = false;
     522             :       fp.handle.SetWeak(&fp, gc_forcing_callback[inner_gc],
     523          20 :                         v8::WeakCallbackType::kParameter);
     524          20 :       invoke_gc[outer_gc]();
     525          20 :       EmptyMessageQueues(isolate);
     526          20 :       CHECK(fp.flag);
     527             :     }
     528           5 :   }
     529           5 : }
     530             : 
     531             : namespace {
     532             : 
     533           5 : void SecondPassCallback(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     534           5 :   data.GetParameter()->flag = true;
     535           5 : }
     536             : 
     537          10 : void FirstPassCallback(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     538             :   data.GetParameter()->handle.Reset();
     539             :   data.SetSecondPassCallback(SecondPassCallback);
     540           5 : }
     541             : 
     542             : }  // namespace
     543             : 
     544       25880 : TEST(SecondPassPhantomCallbacks) {
     545           5 :   v8::Isolate* isolate = CcTest::isolate();
     546           5 :   v8::Locker locker(CcTest::isolate());
     547          10 :   v8::HandleScope scope(isolate);
     548           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     549             :   v8::Context::Scope context_scope(context);
     550             :   FlagAndPersistent fp;
     551           5 :   ConstructJSApiObject(isolate, context, &fp);
     552           5 :   fp.flag = false;
     553             :   fp.handle.SetWeak(&fp, FirstPassCallback, v8::WeakCallbackType::kParameter);
     554           5 :   CHECK(!fp.flag);
     555             :   InvokeMarkSweep();
     556             :   InvokeMarkSweep();
     557          10 :   CHECK(fp.flag);
     558           5 : }
     559             : 
     560       25880 : TEST(MoveStrongGlobal) {
     561           5 :   CcTest::InitializeVM();
     562           5 :   v8::Isolate* isolate = CcTest::isolate();
     563           5 :   v8::HandleScope scope(isolate);
     564             : 
     565           5 :   v8::Global<v8::Object>* global = new Global<v8::Object>();
     566           5 :   ConstructJSObject(isolate, global);
     567             :   InvokeMarkSweep();
     568             :   v8::Global<v8::Object> global2(std::move(*global));
     569          10 :   delete global;
     570           5 :   InvokeMarkSweep();
     571           5 : }
     572             : 
     573       25880 : TEST(MoveWeakGlobal) {
     574           5 :   CcTest::InitializeVM();
     575           5 :   v8::Isolate* isolate = CcTest::isolate();
     576           5 :   v8::HandleScope scope(isolate);
     577             : 
     578           5 :   v8::Global<v8::Object>* global = new Global<v8::Object>();
     579           5 :   ConstructJSObject(isolate, global);
     580             :   InvokeMarkSweep();
     581             :   global->SetWeak();
     582             :   v8::Global<v8::Object> global2(std::move(*global));
     583          10 :   delete global;
     584           5 :   InvokeMarkSweep();
     585           5 : }
     586             : 
     587             : }  // namespace internal
     588       77625 : }  // namespace v8

Generated by: LCOV version 1.10