Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include <unordered_map>
6 : #include <vector>
7 :
8 : #include "include/v8.h"
9 : #include "src/api-inl.h"
10 : #include "src/heap/heap-inl.h"
11 : #include "src/objects-inl.h"
12 : #include "src/objects/module.h"
13 : #include "src/objects/script.h"
14 : #include "src/objects/shared-function-info.h"
15 : #include "test/cctest/cctest.h"
16 : #include "test/cctest/heap/heap-utils.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 : namespace heap {
21 :
22 : namespace {
23 :
24 35 : v8::Local<v8::Object> ConstructTraceableJSApiObject(
25 : v8::Local<v8::Context> context, void* first_field, void* second_field) {
26 35 : v8::EscapableHandleScope scope(context->GetIsolate());
27 : v8::Local<v8::FunctionTemplate> function_t =
28 35 : v8::FunctionTemplate::New(context->GetIsolate());
29 35 : v8::Local<v8::ObjectTemplate> instance_t = function_t->InstanceTemplate();
30 35 : instance_t->SetInternalFieldCount(2);
31 : v8::Local<v8::Function> function =
32 35 : function_t->GetFunction(context).ToLocalChecked();
33 : v8::Local<v8::Object> instance =
34 : function->NewInstance(context).ToLocalChecked();
35 35 : instance->SetAlignedPointerInInternalField(0, first_field);
36 35 : instance->SetAlignedPointerInInternalField(1, second_field);
37 35 : CHECK(!instance.IsEmpty());
38 : i::Handle<i::JSReceiver> js_obj = v8::Utils::OpenHandle(*instance);
39 35 : CHECK_EQ(i::JS_API_OBJECT_TYPE, js_obj->map()->instance_type());
40 35 : return scope.Escape(instance);
41 : }
42 :
43 140 : class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer {
44 : public:
45 140 : TestEmbedderHeapTracer() = default;
46 :
47 15 : void RegisterV8References(
48 15 : const std::vector<std::pair<void*, void*>>& embedder_fields) final {
49 : registered_from_v8_.insert(registered_from_v8_.end(),
50 15 : embedder_fields.begin(), embedder_fields.end());
51 15 : }
52 :
53 : void AddReferenceForTracing(v8::TracedGlobal<v8::Object>* global) {
54 5 : to_register_with_v8_.push_back(global);
55 : }
56 :
57 135 : bool AdvanceTracing(double deadline_in_ms) final {
58 275 : for (auto global : to_register_with_v8_) {
59 5 : RegisterEmbedderReference(global->As<v8::Value>());
60 : }
61 : to_register_with_v8_.clear();
62 135 : return true;
63 : }
64 :
65 450 : bool IsTracingDone() final { return to_register_with_v8_.empty(); }
66 :
67 45 : void TracePrologue() final {}
68 45 : void TraceEpilogue() final {}
69 45 : void EnterFinalPause(EmbedderStackState) final {}
70 :
71 : bool IsRegisteredFromV8(void* first_field) const {
72 30 : for (auto pair : registered_from_v8_) {
73 15 : if (pair.first == first_field) return true;
74 : }
75 : return false;
76 : }
77 :
78 : void ConsiderTracedGlobalAsRoot(bool value) {
79 20 : consider_traced_global_as_root_ = value;
80 : }
81 :
82 15 : bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) final {
83 15 : return consider_traced_global_as_root_;
84 : }
85 :
86 : private:
87 : std::vector<std::pair<void*, void*>> registered_from_v8_;
88 : std::vector<v8::TracedGlobal<v8::Object>*> to_register_with_v8_;
89 : bool consider_traced_global_as_root_ = true;
90 : };
91 :
92 : class TemporaryEmbedderHeapTracerScope {
93 : public:
94 : TemporaryEmbedderHeapTracerScope(v8::Isolate* isolate,
95 : EmbedderHeapTracer* tracer)
96 : : isolate_(isolate) {
97 70 : isolate_->SetEmbedderHeapTracer(tracer);
98 : }
99 :
100 : ~TemporaryEmbedderHeapTracerScope() {
101 70 : isolate_->SetEmbedderHeapTracer(nullptr);
102 : }
103 :
104 : private:
105 : v8::Isolate* const isolate_;
106 : };
107 :
108 : } // namespace
109 :
110 25880 : TEST(V8RegisteringEmbedderReference) {
111 : // Tests that wrappers are properly registered with the embedder heap
112 : // tracer.
113 : ManualGCScope manual_gc;
114 5 : CcTest::InitializeVM();
115 5 : v8::Isolate* isolate = CcTest::isolate();
116 5 : TestEmbedderHeapTracer tracer;
117 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
118 10 : v8::HandleScope scope(isolate);
119 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
120 : v8::Context::Scope context_scope(context);
121 :
122 : void* first_field = reinterpret_cast<void*>(0x2);
123 : v8::Local<v8::Object> api_object =
124 5 : ConstructTraceableJSApiObject(context, first_field, nullptr);
125 5 : CHECK(!api_object.IsEmpty());
126 5 : CcTest::CollectGarbage(i::OLD_SPACE);
127 5 : CHECK(tracer.IsRegisteredFromV8(first_field));
128 5 : }
129 :
130 25880 : TEST(EmbedderRegisteringV8Reference) {
131 : // Tests that references that are registered by the embedder heap tracer are
132 : // considered live by V8.
133 : ManualGCScope manual_gc;
134 5 : CcTest::InitializeVM();
135 5 : v8::Isolate* isolate = CcTest::isolate();
136 5 : TestEmbedderHeapTracer tracer;
137 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
138 10 : v8::HandleScope scope(isolate);
139 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
140 : v8::Context::Scope context_scope(context);
141 :
142 10 : v8::TracedGlobal<v8::Object> g;
143 : {
144 5 : v8::HandleScope inner_scope(isolate);
145 : v8::Local<v8::Object> o =
146 5 : v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
147 5 : g.Reset(isolate, o);
148 : }
149 : tracer.AddReferenceForTracing(&g);
150 5 : CcTest::CollectGarbage(i::OLD_SPACE);
151 5 : CHECK(!g.IsEmpty());
152 5 : }
153 :
154 : namespace {
155 :
156 5 : void ResurrectingFinalizer(
157 5 : const v8::WeakCallbackInfo<v8::Global<v8::Object>>& data) {
158 : data.GetParameter()->ClearWeak();
159 5 : }
160 :
161 : } // namespace
162 :
163 25880 : TEST(TracingInRevivedSubgraph) {
164 : // Tests that wrappers are traced when they are contained with in a subgraph
165 : // that is revived by a finalizer.
166 : ManualGCScope manual_gc;
167 5 : CcTest::InitializeVM();
168 5 : v8::Isolate* isolate = CcTest::isolate();
169 5 : TestEmbedderHeapTracer tracer;
170 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
171 10 : v8::HandleScope scope(isolate);
172 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
173 : v8::Context::Scope context_scope(context);
174 :
175 : v8::Global<v8::Object> g;
176 : void* first_field = reinterpret_cast<void*>(0x4);
177 : {
178 5 : v8::HandleScope inner_scope(isolate);
179 : v8::Local<v8::Object> api_object =
180 5 : ConstructTraceableJSApiObject(context, first_field, nullptr);
181 5 : CHECK(!api_object.IsEmpty());
182 : v8::Local<v8::Object> o =
183 5 : v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
184 15 : o->Set(context, v8_str("link"), api_object).FromJust();
185 : g.Reset(isolate, o);
186 5 : g.SetWeak(&g, ResurrectingFinalizer, v8::WeakCallbackType::kFinalizer);
187 : }
188 5 : CcTest::CollectGarbage(i::OLD_SPACE);
189 5 : CHECK(tracer.IsRegisteredFromV8(first_field));
190 5 : }
191 :
192 25880 : TEST(TracingInEphemerons) {
193 : // Tests that wrappers that are part of ephemerons are traced.
194 : ManualGCScope manual_gc;
195 5 : CcTest::InitializeVM();
196 5 : v8::Isolate* isolate = CcTest::isolate();
197 5 : TestEmbedderHeapTracer tracer;
198 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
199 10 : v8::HandleScope scope(isolate);
200 5 : v8::Local<v8::Context> context = v8::Context::New(isolate);
201 : v8::Context::Scope context_scope(context);
202 :
203 : v8::Local<v8::Object> key =
204 5 : v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
205 : void* first_field = reinterpret_cast<void*>(0x8);
206 : i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
207 5 : Handle<JSWeakMap> weak_map = i_isolate->factory()->NewJSWeakMap();
208 : {
209 5 : v8::HandleScope inner_scope(isolate);
210 : v8::Local<v8::Object> api_object =
211 5 : ConstructTraceableJSApiObject(context, first_field, nullptr);
212 5 : CHECK(!api_object.IsEmpty());
213 : Handle<JSObject> js_key =
214 : handle(JSObject::cast(*v8::Utils::OpenHandle(*key)), i_isolate);
215 : Handle<JSReceiver> js_api_object = v8::Utils::OpenHandle(*api_object);
216 10 : int32_t hash = js_key->GetOrCreateHash(i_isolate)->value();
217 5 : JSWeakCollection::Set(weak_map, js_key, js_api_object, hash);
218 : }
219 5 : CcTest::CollectGarbage(i::OLD_SPACE);
220 5 : CHECK(tracer.IsRegisteredFromV8(first_field));
221 5 : }
222 :
223 25880 : TEST(FinalizeTracingIsNoopWhenNotMarking) {
224 : ManualGCScope manual_gc;
225 5 : CcTest::InitializeVM();
226 5 : v8::Isolate* isolate = CcTest::isolate();
227 : Isolate* i_isolate = CcTest::i_isolate();
228 5 : TestEmbedderHeapTracer tracer;
229 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
230 :
231 : // Finalize a potentially running garbage collection.
232 : i_isolate->heap()->CollectGarbage(OLD_SPACE,
233 5 : GarbageCollectionReason::kTesting);
234 5 : CHECK(i_isolate->heap()->incremental_marking()->IsStopped());
235 :
236 5 : int gc_counter = i_isolate->heap()->gc_count();
237 5 : tracer.FinalizeTracing();
238 5 : CHECK(i_isolate->heap()->incremental_marking()->IsStopped());
239 5 : CHECK_EQ(gc_counter, i_isolate->heap()->gc_count());
240 5 : }
241 :
242 25880 : TEST(FinalizeTracingWhenMarking) {
243 : ManualGCScope manual_gc;
244 5 : CcTest::InitializeVM();
245 5 : v8::Isolate* isolate = CcTest::isolate();
246 : Isolate* i_isolate = CcTest::i_isolate();
247 5 : TestEmbedderHeapTracer tracer;
248 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
249 :
250 : // Finalize a potentially running garbage collection.
251 : i_isolate->heap()->CollectGarbage(OLD_SPACE,
252 5 : GarbageCollectionReason::kTesting);
253 10 : if (i_isolate->heap()->mark_compact_collector()->sweeping_in_progress()) {
254 5 : i_isolate->heap()->mark_compact_collector()->EnsureSweepingCompleted();
255 : }
256 5 : CHECK(i_isolate->heap()->incremental_marking()->IsStopped());
257 :
258 : i::IncrementalMarking* marking = i_isolate->heap()->incremental_marking();
259 5 : marking->Start(i::GarbageCollectionReason::kTesting);
260 : // Sweeping is not runing so we should immediately start marking.
261 5 : CHECK(marking->IsMarking());
262 5 : tracer.FinalizeTracing();
263 5 : CHECK(marking->IsStopped());
264 5 : }
265 :
266 25880 : TEST(GarbageCollectionForTesting) {
267 : ManualGCScope manual_gc;
268 5 : i::FLAG_expose_gc = true;
269 5 : CcTest::InitializeVM();
270 5 : v8::Isolate* isolate = CcTest::isolate();
271 : Isolate* i_isolate = CcTest::i_isolate();
272 5 : TestEmbedderHeapTracer tracer;
273 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
274 :
275 5 : int saved_gc_counter = i_isolate->heap()->gc_count();
276 5 : tracer.GarbageCollectionForTesting(EmbedderHeapTracer::kUnknown);
277 10 : CHECK_GT(i_isolate->heap()->gc_count(), saved_gc_counter);
278 5 : }
279 :
280 : namespace {
281 :
282 35 : void ConstructJSObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
283 : v8::TracedGlobal<v8::Object>* global) {
284 35 : v8::HandleScope scope(isolate);
285 35 : v8::Local<v8::Object> object(v8::Object::New(isolate));
286 35 : CHECK(!object.IsEmpty());
287 35 : *global = v8::TracedGlobal<v8::Object>(isolate, object);
288 35 : CHECK(!global->IsEmpty());
289 35 : }
290 :
291 20 : void ConstructJSApiObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
292 : v8::TracedGlobal<v8::Object>* global) {
293 20 : v8::HandleScope scope(isolate);
294 : v8::Local<v8::Object> object(
295 20 : ConstructTraceableJSApiObject(context, nullptr, nullptr));
296 20 : CHECK(!object.IsEmpty());
297 20 : *global = v8::TracedGlobal<v8::Object>(isolate, object);
298 20 : CHECK(!global->IsEmpty());
299 20 : }
300 :
301 : enum class SurvivalMode { kSurvives, kDies };
302 :
303 : template <typename ModifierFunction, typename ConstructTracedGlobalFunction>
304 30 : void TracedGlobalTest(v8::Isolate* isolate,
305 : ConstructTracedGlobalFunction construct_function,
306 : ModifierFunction modifier_function, void (*gc_function)(),
307 : SurvivalMode survives) {
308 30 : v8::HandleScope scope(isolate);
309 30 : v8::Local<v8::Context> context = v8::Context::New(isolate);
310 : v8::Context::Scope context_scope(context);
311 :
312 60 : v8::TracedGlobal<v8::Object> global;
313 30 : construct_function(isolate, context, &global);
314 30 : CHECK(InYoungGeneration(isolate, global));
315 5 : modifier_function(global);
316 30 : gc_function();
317 50 : CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !global.IsEmpty());
318 70 : CHECK_IMPLIES(survives == SurvivalMode::kDies, global.IsEmpty());
319 30 : }
320 :
321 : } // namespace
322 :
323 25880 : TEST(TracedGlobalReset) {
324 5 : CcTest::InitializeVM();
325 5 : v8::Isolate* isolate = CcTest::isolate();
326 5 : v8::HandleScope scope(isolate);
327 :
328 10 : v8::TracedGlobal<v8::Object> traced;
329 5 : ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced);
330 5 : CHECK(!traced.IsEmpty());
331 : traced.Reset();
332 10 : CHECK(traced.IsEmpty());
333 5 : }
334 :
335 25880 : TEST(TracedGlobalInStdVector) {
336 : ManualGCScope manual_gc;
337 5 : CcTest::InitializeVM();
338 5 : v8::Isolate* isolate = CcTest::isolate();
339 10 : v8::HandleScope scope(isolate);
340 :
341 5 : std::vector<v8::TracedGlobal<v8::Object>> vec;
342 : {
343 5 : v8::HandleScope scope(isolate);
344 5 : vec.emplace_back(isolate, v8::Object::New(isolate));
345 : }
346 10 : CHECK(!vec[0].IsEmpty());
347 5 : InvokeMarkSweep();
348 10 : CHECK(vec[0].IsEmpty());
349 5 : }
350 :
351 25880 : TEST(TracedGlobalInStdUnorderedMap) {
352 : ManualGCScope manual_gc;
353 5 : CcTest::InitializeVM();
354 5 : v8::Isolate* isolate = CcTest::isolate();
355 10 : v8::HandleScope scope(isolate);
356 :
357 5 : std::unordered_map<int, v8::TracedGlobal<v8::Object>> map;
358 : {
359 5 : v8::HandleScope scope(isolate);
360 : map.emplace(std::piecewise_construct, std::forward_as_tuple(1),
361 15 : std::forward_as_tuple(isolate, v8::Object::New(isolate)));
362 : }
363 10 : CHECK(!map[1].IsEmpty());
364 5 : InvokeMarkSweep();
365 10 : CHECK(map[1].IsEmpty());
366 5 : }
367 :
368 25880 : TEST(TracedGlobalToUnmodifiedJSObjectDiesOnMarkSweep) {
369 5 : CcTest::InitializeVM();
370 : TracedGlobalTest(
371 : CcTest::isolate(), ConstructJSObject,
372 : [](const TracedGlobal<v8::Object>& global) {}, InvokeMarkSweep,
373 5 : SurvivalMode::kDies);
374 5 : }
375 :
376 25880 : TEST(TracedGlobalToUnmodifiedJSObjectSurvivesMarkSweepWhenHeldAliveOtherwise) {
377 5 : CcTest::InitializeVM();
378 5 : v8::Isolate* isolate = CcTest::isolate();
379 : v8::Global<v8::Object> strong_global;
380 : TracedGlobalTest(
381 : CcTest::isolate(), ConstructJSObject,
382 5 : [isolate, &strong_global](const TracedGlobal<v8::Object>& global) {
383 5 : v8::HandleScope scope(isolate);
384 20 : strong_global = v8::Global<v8::Object>(isolate, global.Get(isolate));
385 5 : },
386 5 : InvokeMarkSweep, SurvivalMode::kSurvives);
387 5 : }
388 :
389 25880 : TEST(TracedGlobalToUnmodifiedJSObjectSurvivesScavenge) {
390 : ManualGCScope manual_gc;
391 5 : CcTest::InitializeVM();
392 : TracedGlobalTest(
393 : CcTest::isolate(), ConstructJSObject,
394 : [](const TracedGlobal<v8::Object>& global) {}, InvokeScavenge,
395 5 : SurvivalMode::kSurvives);
396 5 : }
397 :
398 25880 : TEST(TracedGlobalToUnmodifiedJSObjectSurvivesScavengeWhenExcludedFromRoots) {
399 : ManualGCScope manual_gc;
400 5 : CcTest::InitializeVM();
401 5 : v8::Isolate* isolate = CcTest::isolate();
402 5 : TestEmbedderHeapTracer tracer;
403 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
404 : tracer.ConsiderTracedGlobalAsRoot(false);
405 : TracedGlobalTest(
406 : CcTest::isolate(), ConstructJSObject,
407 : [](const TracedGlobal<v8::Object>& global) {}, InvokeScavenge,
408 5 : SurvivalMode::kSurvives);
409 5 : }
410 :
411 25880 : TEST(TracedGlobalToUnmodifiedJSApiObjectSurvivesScavengePerDefault) {
412 : ManualGCScope manual_gc;
413 5 : CcTest::InitializeVM();
414 5 : v8::Isolate* isolate = CcTest::isolate();
415 5 : TestEmbedderHeapTracer tracer;
416 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
417 : tracer.ConsiderTracedGlobalAsRoot(true);
418 : TracedGlobalTest(
419 : CcTest::isolate(), ConstructJSApiObject,
420 : [](const TracedGlobal<v8::Object>& global) {}, InvokeScavenge,
421 5 : SurvivalMode::kSurvives);
422 5 : }
423 :
424 25880 : TEST(TracedGlobalToUnmodifiedJSApiObjectDiesOnScavengeWhenExcludedFromRoots) {
425 : ManualGCScope manual_gc;
426 5 : CcTest::InitializeVM();
427 5 : v8::Isolate* isolate = CcTest::isolate();
428 5 : TestEmbedderHeapTracer tracer;
429 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
430 : tracer.ConsiderTracedGlobalAsRoot(false);
431 : TracedGlobalTest(
432 : CcTest::isolate(), ConstructJSApiObject,
433 : [](const TracedGlobal<v8::Object>& global) {}, InvokeScavenge,
434 5 : SurvivalMode::kDies);
435 5 : }
436 :
437 25880 : TEST(TracedGlobalWrapperClassId) {
438 : ManualGCScope manual_gc;
439 5 : CcTest::InitializeVM();
440 5 : v8::Isolate* isolate = CcTest::isolate();
441 10 : v8::HandleScope scope(isolate);
442 5 : TestEmbedderHeapTracer tracer;
443 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
444 :
445 10 : v8::TracedGlobal<v8::Object> traced;
446 5 : ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced);
447 5 : CHECK_EQ(0, traced.WrapperClassId());
448 : traced.SetWrapperClassId(17);
449 5 : CHECK_EQ(17, traced.WrapperClassId());
450 5 : }
451 :
452 : namespace {
453 :
454 : class TracedGlobalVisitor final
455 : : public v8::EmbedderHeapTracer::TracedGlobalHandleVisitor {
456 : public:
457 5 : ~TracedGlobalVisitor() override = default;
458 5 : void VisitTracedGlobalHandle(const TracedGlobal<Value>& value) final {
459 5 : if (value.WrapperClassId() == 57) {
460 5 : count_++;
461 : }
462 5 : }
463 :
464 : size_t count() const { return count_; }
465 :
466 : private:
467 : size_t count_ = 0;
468 : };
469 :
470 : } // namespace
471 :
472 25880 : TEST(TracedGlobalIteration) {
473 : ManualGCScope manual_gc;
474 5 : CcTest::InitializeVM();
475 5 : v8::Isolate* isolate = CcTest::isolate();
476 10 : v8::HandleScope scope(isolate);
477 5 : TestEmbedderHeapTracer tracer;
478 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
479 :
480 10 : v8::TracedGlobal<v8::Object> traced;
481 5 : ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced);
482 5 : CHECK(!traced.IsEmpty());
483 : traced.SetWrapperClassId(57);
484 5 : TracedGlobalVisitor visitor;
485 : {
486 5 : v8::HandleScope scope(isolate);
487 5 : tracer.IterateTracedGlobalHandles(&visitor);
488 : }
489 10 : CHECK_EQ(1, visitor.count());
490 5 : }
491 :
492 : namespace {
493 :
494 10 : void FinalizationCallback(const WeakCallbackInfo<void>& data) {
495 : v8::TracedGlobal<v8::Object>* traced =
496 : reinterpret_cast<v8::TracedGlobal<v8::Object>*>(data.GetParameter());
497 10 : CHECK_EQ(reinterpret_cast<void*>(0x4), data.GetInternalField(0));
498 10 : CHECK_EQ(reinterpret_cast<void*>(0x8), data.GetInternalField(1));
499 : traced->Reset();
500 10 : }
501 :
502 : } // namespace
503 :
504 25880 : TEST(TracedGlobalSetFinalizationCallbackScavenge) {
505 : ManualGCScope manual_gc;
506 5 : CcTest::InitializeVM();
507 5 : v8::Isolate* isolate = CcTest::isolate();
508 10 : v8::HandleScope scope(isolate);
509 5 : TestEmbedderHeapTracer tracer;
510 : tracer.ConsiderTracedGlobalAsRoot(false);
511 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
512 :
513 10 : v8::TracedGlobal<v8::Object> traced;
514 5 : ConstructJSApiObject(isolate, isolate->GetCurrentContext(), &traced);
515 5 : CHECK(!traced.IsEmpty());
516 : {
517 5 : v8::HandleScope scope(isolate);
518 : auto local = traced.Get(isolate);
519 5 : local->SetAlignedPointerInInternalField(0, reinterpret_cast<void*>(0x4));
520 5 : local->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0x8));
521 : }
522 : traced.SetFinalizationCallback(&traced, FinalizationCallback);
523 5 : heap::InvokeScavenge();
524 5 : CHECK(traced.IsEmpty());
525 5 : }
526 :
527 25880 : TEST(TracedGlobalSetFinalizationCallbackMarkSweep) {
528 : ManualGCScope manual_gc;
529 5 : CcTest::InitializeVM();
530 5 : v8::Isolate* isolate = CcTest::isolate();
531 10 : v8::HandleScope scope(isolate);
532 5 : TestEmbedderHeapTracer tracer;
533 : TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
534 :
535 10 : v8::TracedGlobal<v8::Object> traced;
536 5 : ConstructJSApiObject(isolate, isolate->GetCurrentContext(), &traced);
537 5 : CHECK(!traced.IsEmpty());
538 : {
539 5 : v8::HandleScope scope(isolate);
540 : auto local = traced.Get(isolate);
541 5 : local->SetAlignedPointerInInternalField(0, reinterpret_cast<void*>(0x4));
542 5 : local->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0x8));
543 : }
544 : traced.SetFinalizationCallback(&traced, FinalizationCallback);
545 5 : heap::InvokeMarkSweep();
546 5 : CHECK(traced.IsEmpty());
547 5 : }
548 :
549 : } // namespace heap
550 : } // namespace internal
551 77625 : } // namespace v8
|