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
|