LCOV - code coverage report
Current view: top level - test/cctest - test-global-handles.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 247 248 99.6 %
Date: 2019-01-20 Functions: 52 53 98.1 %

          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/isolate.h"
      32             : #include "src/objects-inl.h"
      33             : #include "test/cctest/cctest.h"
      34             : 
      35             : namespace v8 {
      36             : namespace internal {
      37             : 
      38             : namespace {
      39             : 
      40          45 : void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
      41             : 
      42          75 : void InvokeMarkSweep() { CcTest::CollectAllGarbage(); }
      43             : 
      44         130 : void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
      45          65 :   info.GetReturnValue().Set(v8_num(0));
      46          65 : }
      47             : 
      48             : struct FlagAndPersistent {
      49             :   bool flag;
      50             :   v8::Global<v8::Object> handle;
      51             : };
      52             : 
      53          20 : void ResetHandleAndSetFlag(
      54          40 :     const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
      55             :   data.GetParameter()->handle.Reset();
      56          20 :   data.GetParameter()->flag = true;
      57          20 : }
      58             : 
      59             : using ConstructFunction = void (*)(v8::Isolate* isolate,
      60             :                                    v8::Local<v8::Context> context,
      61             :                                    FlagAndPersistent* flag_and_persistent);
      62             : 
      63          15 : void ConstructJSObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
      64             :                        FlagAndPersistent* flag_and_persistent) {
      65          15 :   v8::HandleScope handle_scope(isolate);
      66          15 :   v8::Local<v8::Object> object(v8::Object::New(isolate));
      67          15 :   CHECK(!object.IsEmpty());
      68             :   flag_and_persistent->handle.Reset(isolate, object);
      69          15 :   CHECK(!flag_and_persistent->handle.IsEmpty());
      70          15 : }
      71             : 
      72          65 : void ConstructJSApiObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
      73             :                           FlagAndPersistent* flag_and_persistent) {
      74          65 :   v8::HandleScope handle_scope(isolate);
      75             :   v8::Local<v8::FunctionTemplate> fun =
      76          65 :       v8::FunctionTemplate::New(isolate, SimpleCallback);
      77             :   v8::Local<v8::Object> object = fun->GetFunction(context)
      78          65 :                                      .ToLocalChecked()
      79             :                                      ->NewInstance(context)
      80             :                                      .ToLocalChecked();
      81          65 :   CHECK(!object.IsEmpty());
      82             :   flag_and_persistent->handle.Reset(isolate, object);
      83          65 :   CHECK(!flag_and_persistent->handle.IsEmpty());
      84          65 : }
      85             : 
      86             : enum class SurvivalMode { kSurvives, kDies };
      87             : 
      88             : template <typename ModifierFunction, typename GCFunction>
      89          50 : void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function,
      90             :                     ModifierFunction modifier_function, GCFunction gc_function,
      91             :                     SurvivalMode survives) {
      92          50 :   v8::HandleScope scope(isolate);
      93          50 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
      94             :   v8::Context::Scope context_scope(context);
      95             : 
      96             :   FlagAndPersistent fp;
      97          50 :   construct_function(isolate, context, &fp);
      98             :   {
      99          50 :     v8::HandleScope scope(isolate);
     100             :     v8::Local<v8::Object> tmp = v8::Local<v8::Object>::New(isolate, fp.handle);
     101          50 :     CHECK(i::Heap::InNewSpace(*v8::Utils::OpenHandle(*tmp)));
     102             :   }
     103             : 
     104             :   fp.handle.SetWeak(&fp, &ResetHandleAndSetFlag,
     105             :                     v8::WeakCallbackType::kParameter);
     106          50 :   fp.flag = false;
     107          20 :   modifier_function(&fp);
     108             :   gc_function();
     109          50 :   CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !fp.flag);
     110         100 :   CHECK_IMPLIES(survives == SurvivalMode::kDies, fp.flag);
     111          50 : }
     112             : 
     113           5 : void ResurrectingFinalizer(
     114           5 :     const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
     115             :   data.GetParameter()->ClearWeak();
     116           5 : }
     117             : 
     118           5 : void ResettingFinalizer(
     119           5 :     const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
     120             :   data.GetParameter()->Reset();
     121           5 : }
     122             : 
     123           0 : void EmptyWeakCallback(const v8::WeakCallbackInfo<void>& data) {}
     124             : 
     125           5 : void ResurrectingFinalizerSettingProperty(
     126          15 :     const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
     127             :   data.GetParameter()->ClearWeak();
     128             :   v8::Local<v8::Object> o =
     129             :       v8::Local<v8::Object>::New(data.GetIsolate(), *data.GetParameter());
     130             :   o->Set(data.GetIsolate()->GetCurrentContext(), v8_str("finalizer"),
     131          20 :          v8_str("was here"))
     132          10 :       .FromJust();
     133           5 : }
     134             : 
     135             : }  // namespace
     136             : 
     137       28342 : TEST(EternalHandles) {
     138           5 :   CcTest::InitializeVM();
     139           5 :   Isolate* isolate = CcTest::i_isolate();
     140             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     141          15 :   EternalHandles* eternal_handles = isolate->eternal_handles();
     142             : 
     143             :   // Create a number of handles that will not be on a block boundary
     144             :   const int kArrayLength = 2048-1;
     145             :   int indices[kArrayLength];
     146       10240 :   v8::Eternal<v8::Value> eternals[kArrayLength];
     147             : 
     148           5 :   CHECK_EQ(0, eternal_handles->NumberOfHandles());
     149       10235 :   for (int i = 0; i < kArrayLength; i++) {
     150       10235 :     indices[i] = -1;
     151             :     HandleScope scope(isolate);
     152       10235 :     v8::Local<v8::Object> object = v8::Object::New(v8_isolate);
     153             :     object->Set(v8_isolate->GetCurrentContext(), i,
     154       30705 :                 v8::Integer::New(v8_isolate, i))
     155       20470 :         .FromJust();
     156             :     // Create with internal api
     157             :     eternal_handles->Create(
     158       20470 :         isolate, *v8::Utils::OpenHandle(*object), &indices[i]);
     159             :     // Create with external api
     160       20470 :     CHECK(eternals[i].IsEmpty());
     161             :     eternals[i].Set(v8_isolate, object);
     162       10235 :     CHECK(!eternals[i].IsEmpty());
     163             :   }
     164             : 
     165           5 :   CcTest::CollectAllAvailableGarbage();
     166             : 
     167       10240 :   for (int i = 0; i < kArrayLength; i++) {
     168       20470 :     for (int j = 0; j < 2; j++) {
     169             :       HandleScope scope(isolate);
     170             :       v8::Local<v8::Value> local;
     171       20470 :       if (j == 0) {
     172             :         // Test internal api
     173       10235 :         local = v8::Utils::ToLocal(eternal_handles->Get(indices[i]));
     174             :       } else {
     175             :         // Test external api
     176       10235 :         local = eternals[i].Get(v8_isolate);
     177             :       }
     178             :       v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(local);
     179             :       v8::Local<v8::Value> value =
     180       20470 :           object->Get(v8_isolate->GetCurrentContext(), i).ToLocalChecked();
     181       20470 :       CHECK(value->IsInt32());
     182       40940 :       CHECK_EQ(i,
     183             :                value->Int32Value(v8_isolate->GetCurrentContext()).FromJust());
     184             :     }
     185             :   }
     186             : 
     187           5 :   CHECK_EQ(2*kArrayLength, eternal_handles->NumberOfHandles());
     188             : 
     189             :   // Create an eternal via the constructor
     190             :   {
     191             :     HandleScope scope(isolate);
     192           5 :     v8::Local<v8::Object> object = v8::Object::New(v8_isolate);
     193             :     v8::Eternal<v8::Object> eternal(v8_isolate, object);
     194           5 :     CHECK(!eternal.IsEmpty());
     195           5 :     CHECK(object == eternal.Get(v8_isolate));
     196             :   }
     197             : 
     198           5 :   CHECK_EQ(2*kArrayLength + 1, eternal_handles->NumberOfHandles());
     199           5 : }
     200             : 
     201             : 
     202       28342 : TEST(PersistentBaseGetLocal) {
     203           5 :   CcTest::InitializeVM();
     204           5 :   v8::Isolate* isolate = CcTest::isolate();
     205             : 
     206           5 :   v8::HandleScope scope(isolate);
     207           5 :   v8::Local<v8::Object> o = v8::Object::New(isolate);
     208           5 :   CHECK(!o.IsEmpty());
     209             :   v8::Persistent<v8::Object> p(isolate, o);
     210           5 :   CHECK(o == p.Get(isolate));
     211           5 :   CHECK(v8::Local<v8::Object>::New(isolate, p) == p.Get(isolate));
     212             : 
     213             :   v8::Global<v8::Object> g(isolate, o);
     214           5 :   CHECK(o == g.Get(isolate));
     215          10 :   CHECK(v8::Local<v8::Object>::New(isolate, g) == g.Get(isolate));
     216           5 : }
     217             : 
     218       28342 : TEST(WeakPersistentSmi) {
     219           5 :   CcTest::InitializeVM();
     220           5 :   v8::Isolate* isolate = CcTest::isolate();
     221             : 
     222           5 :   v8::HandleScope scope(isolate);
     223           5 :   v8::Local<v8::Number> n = v8::Number::New(isolate, 0);
     224             :   v8::Global<v8::Number> g(isolate, n);
     225             : 
     226             :   // Should not crash.
     227             :   g.SetWeak<void>(nullptr, &EmptyWeakCallback,
     228           5 :                   v8::WeakCallbackType::kParameter);
     229           5 : }
     230             : 
     231       28342 : TEST(FinalizerWeakness) {
     232           5 :   CcTest::InitializeVM();
     233           5 :   v8::Isolate* isolate = CcTest::isolate();
     234             : 
     235             :   v8::Global<v8::Object> g;
     236             :   int identity;
     237             : 
     238             :   {
     239           5 :     v8::HandleScope scope(isolate);
     240           5 :     v8::Local<v8::Object> o = v8::Object::New(isolate);
     241           5 :     identity = o->GetIdentityHash();
     242             :     g.Reset(isolate, o);
     243             :     g.SetWeak(&g, &ResurrectingFinalizerSettingProperty,
     244           5 :               v8::WeakCallbackType::kFinalizer);
     245             :   }
     246             : 
     247           5 :   CcTest::CollectAllAvailableGarbage();
     248             : 
     249           5 :   CHECK(!g.IsEmpty());
     250          10 :   v8::HandleScope scope(isolate);
     251             :   v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, g);
     252           5 :   CHECK_EQ(identity, o->GetIdentityHash());
     253          15 :   CHECK(o->Has(isolate->GetCurrentContext(), v8_str("finalizer")).FromJust());
     254           5 : }
     255             : 
     256       28342 : TEST(PhatomHandlesWithoutCallbacks) {
     257           5 :   CcTest::InitializeVM();
     258           5 :   v8::Isolate* isolate = CcTest::isolate();
     259             : 
     260             :   v8::Global<v8::Object> g1, g2;
     261             :   {
     262           5 :     v8::HandleScope scope(isolate);
     263          10 :     g1.Reset(isolate, v8::Object::New(isolate));
     264             :     g1.SetWeak();
     265          10 :     g2.Reset(isolate, v8::Object::New(isolate));
     266           5 :     g2.SetWeak();
     267             :   }
     268             : 
     269           5 :   CHECK_EQ(0u, isolate->NumberOfPhantomHandleResetsSinceLastCall());
     270           5 :   CcTest::CollectAllAvailableGarbage();
     271           5 :   CHECK_EQ(2u, isolate->NumberOfPhantomHandleResetsSinceLastCall());
     272           5 :   CHECK_EQ(0u, isolate->NumberOfPhantomHandleResetsSinceLastCall());
     273           5 : }
     274             : 
     275       28342 : TEST(WeakHandleToUnmodifiedJSObjectSurvivesScavenge) {
     276           5 :   CcTest::InitializeVM();
     277             :   WeakHandleTest(
     278             :       CcTest::isolate(), &ConstructJSObject, [](FlagAndPersistent* fp) {},
     279           5 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     280           5 : }
     281             : 
     282       28342 : TEST(WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact) {
     283           5 :   CcTest::InitializeVM();
     284             :   WeakHandleTest(
     285             :       CcTest::isolate(), &ConstructJSObject, [](FlagAndPersistent* fp) {},
     286           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kDies);
     287           5 : }
     288             : 
     289       28342 : TEST(WeakHandleToUnmodifiedJSObjectSurvivesMarkCompactWhenInHandle) {
     290           5 :   CcTest::InitializeVM();
     291             :   WeakHandleTest(
     292             :       CcTest::isolate(), &ConstructJSObject,
     293           5 :       [](FlagAndPersistent* fp) {
     294             :         v8::Local<v8::Object> handle =
     295           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     296             :         USE(handle);
     297           5 :       },
     298           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
     299           5 : }
     300             : 
     301       28342 : TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnScavenge) {
     302           5 :   CcTest::InitializeVM();
     303             :   WeakHandleTest(
     304             :       CcTest::isolate(), &ConstructJSApiObject, [](FlagAndPersistent* fp) {},
     305           5 :       []() { InvokeScavenge(); }, SurvivalMode::kDies);
     306           5 : }
     307             : 
     308       28342 : TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesScavengeWhenInHandle) {
     309           5 :   CcTest::InitializeVM();
     310             :   WeakHandleTest(
     311             :       CcTest::isolate(), &ConstructJSApiObject,
     312           5 :       [](FlagAndPersistent* fp) {
     313             :         v8::Local<v8::Object> handle =
     314           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     315             :         USE(handle);
     316           5 :       },
     317           5 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     318           5 : }
     319             : 
     320       28342 : TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnMarkCompact) {
     321           5 :   CcTest::InitializeVM();
     322             :   WeakHandleTest(
     323             :       CcTest::isolate(), &ConstructJSApiObject, [](FlagAndPersistent* fp) {},
     324           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kDies);
     325           5 : }
     326             : 
     327       28342 : TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) {
     328           5 :   CcTest::InitializeVM();
     329             :   WeakHandleTest(
     330             :       CcTest::isolate(), &ConstructJSApiObject,
     331           5 :       [](FlagAndPersistent* fp) {
     332             :         v8::Local<v8::Object> handle =
     333           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     334             :         USE(handle);
     335           5 :       },
     336           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
     337           5 : }
     338             : 
     339       28342 : TEST(WeakHandleToActiveUnmodifiedJSApiObjectSurvivesScavenge) {
     340           5 :   CcTest::InitializeVM();
     341             :   WeakHandleTest(
     342             :       CcTest::isolate(), &ConstructJSApiObject,
     343             :       [](FlagAndPersistent* fp) { fp->handle.MarkActive(); },
     344           5 :       []() { InvokeScavenge(); }, SurvivalMode::kSurvives);
     345           5 : }
     346             : 
     347       28342 : TEST(WeakHandleToActiveUnmodifiedJSApiObjectDiesOnMarkCompact) {
     348           5 :   CcTest::InitializeVM();
     349             :   WeakHandleTest(
     350             :       CcTest::isolate(), &ConstructJSApiObject,
     351             :       [](FlagAndPersistent* fp) { fp->handle.MarkActive(); },
     352           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kDies);
     353           5 : }
     354             : 
     355       28342 : TEST(WeakHandleToActiveUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) {
     356           5 :   CcTest::InitializeVM();
     357             :   WeakHandleTest(
     358             :       CcTest::isolate(), &ConstructJSApiObject,
     359           5 :       [](FlagAndPersistent* fp) {
     360             :         fp->handle.MarkActive();
     361             :         v8::Local<v8::Object> handle =
     362           5 :             v8::Local<v8::Object>::New(CcTest::isolate(), fp->handle);
     363             :         USE(handle);
     364           5 :       },
     365           5 :       []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
     366           5 : }
     367             : 
     368       28342 : TEST(FinalizerOnUnmodifiedJSApiObjectDoesNotCrash) {
     369             :   // See crbug.com/v8/8586.
     370           5 :   CcTest::InitializeVM();
     371           5 :   v8::Isolate* isolate = CcTest::isolate();
     372           5 :   v8::HandleScope scope(isolate);
     373           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     374             :   v8::Context::Scope context_scope(context);
     375             : 
     376             :   FlagAndPersistent fp;
     377             :   // Could use a regular object and MarkIndependent too.
     378           5 :   ConstructJSApiObject(isolate, context, &fp);
     379             :   fp.handle.SetWeak(&fp, &ResetHandleAndSetFlag,
     380             :                     v8::WeakCallbackType::kFinalizer);
     381           5 :   fp.flag = false;
     382             :   {
     383           5 :     v8::HandleScope scope(isolate);
     384             :     v8::Local<v8::Object> tmp = v8::Local<v8::Object>::New(isolate, fp.handle);
     385             :     USE(tmp);
     386           5 :     InvokeScavenge();
     387           5 :   }
     388           5 : }
     389             : 
     390             : namespace {
     391             : 
     392          10 : void ConstructFinalizerPointingPhantomHandle(
     393             :     v8::Isolate* isolate, v8::Global<v8::Object>* g1,
     394             :     v8::Global<v8::Object>* g2,
     395             :     typename v8::WeakCallbackInfo<v8::Global<v8::Object>>::Callback
     396             :         finalizer_for_g1) {
     397          10 :   v8::HandleScope scope(isolate);
     398             :   v8::Local<v8::Object> o1 =
     399          10 :       v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     400             :   v8::Local<v8::Object> o2 =
     401          10 :       v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
     402          30 :   o1->Set(isolate->GetCurrentContext(), v8_str("link"), o2).FromJust();
     403             :   g1->Reset(isolate, o1);
     404             :   g2->Reset(isolate, o2);
     405             :   // g1 will be finalized but resurrected.
     406             :   g1->SetWeak(g1, finalizer_for_g1, v8::WeakCallbackType::kFinalizer);
     407             :   // g2 will be a phantom handle that is dependent on the finalizer handle
     408             :   // g1 as it is in its subgraph.
     409          10 :   g2->SetWeak();
     410          10 : }
     411             : 
     412             : }  // namespace
     413             : 
     414       28342 : TEST(FinalizerResurrectsAndKeepsPhantomAliveOnMarkCompact) {
     415             :   // See crbug.com/772299.
     416           5 :   CcTest::InitializeVM();
     417             :   v8::Global<v8::Object> g1, g2;
     418             :   ConstructFinalizerPointingPhantomHandle(CcTest::isolate(), &g1, &g2,
     419           5 :                                           ResurrectingFinalizer);
     420             :   InvokeMarkSweep();
     421             :   // Both, g1 and g2, should stay alive as the finalizer resurrects the root
     422             :   // object that transitively keeps the other one alive.
     423           5 :   CHECK(!g1.IsEmpty());
     424           5 :   CHECK(!g2.IsEmpty());
     425             :   InvokeMarkSweep();
     426             :   // The finalizer handle is now strong, so it should keep the objects alive.
     427           5 :   CHECK(!g1.IsEmpty());
     428           5 :   CHECK(!g2.IsEmpty());
     429           5 : }
     430             : 
     431       28342 : TEST(FinalizerDiesAndKeepsPhantomAliveOnMarkCompact) {
     432           5 :   CcTest::InitializeVM();
     433             :   v8::Global<v8::Object> g1, g2;
     434             :   ConstructFinalizerPointingPhantomHandle(CcTest::isolate(), &g1, &g2,
     435           5 :                                           ResettingFinalizer);
     436             :   InvokeMarkSweep();
     437             :   // Finalizer (g1) dies but the phantom handle (g2) is kept alive for one
     438             :   // more round as the underlying object only dies on the next GC.
     439           5 :   CHECK(g1.IsEmpty());
     440           5 :   CHECK(!g2.IsEmpty());
     441             :   InvokeMarkSweep();
     442             :   // Phantom handle dies after one more round.
     443           5 :   CHECK(g1.IsEmpty());
     444           5 :   CHECK(g2.IsEmpty());
     445           5 : }
     446             : 
     447             : namespace {
     448             : 
     449          10 : void ForceScavenge2(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     450          10 :   data.GetParameter()->flag = true;
     451             :   InvokeScavenge();
     452          10 : }
     453             : 
     454          20 : void ForceScavenge1(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     455             :   data.GetParameter()->handle.Reset();
     456             :   data.SetSecondPassCallback(ForceScavenge2);
     457          10 : }
     458             : 
     459          10 : void ForceMarkSweep2(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     460          10 :   data.GetParameter()->flag = true;
     461             :   InvokeMarkSweep();
     462          10 : }
     463             : 
     464          20 : void ForceMarkSweep1(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     465             :   data.GetParameter()->handle.Reset();
     466             :   data.SetSecondPassCallback(ForceMarkSweep2);
     467          10 : }
     468             : 
     469             : }  // namespace
     470             : 
     471       28342 : TEST(GCFromWeakCallbacks) {
     472           5 :   v8::Isolate* isolate = CcTest::isolate();
     473           5 :   v8::Locker locker(CcTest::isolate());
     474          10 :   v8::HandleScope scope(isolate);
     475           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     476             :   v8::Context::Scope context_scope(context);
     477             : 
     478             :   static const int kNumberOfGCTypes = 2;
     479             :   typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
     480             :   Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
     481           5 :                                                     &ForceMarkSweep1};
     482             : 
     483             :   typedef void (*GCInvoker)();
     484           5 :   GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
     485             : 
     486          15 :   for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
     487          20 :     for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
     488             :       FlagAndPersistent fp;
     489          20 :       ConstructJSApiObject(isolate, context, &fp);
     490             :       {
     491          20 :         v8::HandleScope scope(isolate);
     492             :         v8::Local<v8::Object> tmp =
     493             :             v8::Local<v8::Object>::New(isolate, fp.handle);
     494          20 :         CHECK(i::Heap::InNewSpace(*v8::Utils::OpenHandle(*tmp)));
     495             :       }
     496          20 :       fp.flag = false;
     497             :       fp.handle.SetWeak(&fp, gc_forcing_callback[inner_gc],
     498          20 :                         v8::WeakCallbackType::kParameter);
     499          20 :       invoke_gc[outer_gc]();
     500          20 :       EmptyMessageQueues(isolate);
     501          20 :       CHECK(fp.flag);
     502             :     }
     503           5 :   }
     504           5 : }
     505             : 
     506             : namespace {
     507             : 
     508           5 : void SecondPassCallback(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     509           5 :   data.GetParameter()->flag = true;
     510           5 : }
     511             : 
     512          10 : void FirstPassCallback(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
     513             :   data.GetParameter()->handle.Reset();
     514             :   data.SetSecondPassCallback(SecondPassCallback);
     515           5 : }
     516             : 
     517             : }  // namespace
     518             : 
     519       28342 : TEST(SecondPassPhantomCallbacks) {
     520           5 :   v8::Isolate* isolate = CcTest::isolate();
     521           5 :   v8::Locker locker(CcTest::isolate());
     522          10 :   v8::HandleScope scope(isolate);
     523           5 :   v8::Local<v8::Context> context = v8::Context::New(isolate);
     524             :   v8::Context::Scope context_scope(context);
     525             :   FlagAndPersistent fp;
     526           5 :   ConstructJSApiObject(isolate, context, &fp);
     527           5 :   fp.flag = false;
     528             :   fp.handle.SetWeak(&fp, FirstPassCallback, v8::WeakCallbackType::kParameter);
     529           5 :   CHECK(!fp.flag);
     530             :   InvokeMarkSweep();
     531             :   InvokeMarkSweep();
     532          10 :   CHECK(fp.flag);
     533           5 : }
     534             : 
     535             : }  // namespace internal
     536       85011 : }  // namespace v8

Generated by: LCOV version 1.10