Flutter Engine
The Flutter Engine
heap_test.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include <map>
6#include <memory>
7#include <set>
8#include <string>
9
10#include "platform/globals.h"
11
12#include "platform/assert.h"
13#include "vm/class_finalizer.h"
14#include "vm/dart_api_impl.h"
15#include "vm/globals.h"
16#include "vm/heap/become.h"
17#include "vm/heap/heap.h"
18#include "vm/message_handler.h"
19#include "vm/message_snapshot.h"
20#include "vm/object_graph.h"
21#include "vm/port.h"
22#include "vm/symbols.h"
23#include "vm/unit_test.h"
24
25namespace dart {
26
27DECLARE_FLAG(int, early_tenuring_threshold);
28
29TEST_CASE(OldGC) {
30 const char* kScriptChars =
31 "main() {\n"
32 " return [1, 2, 3];\n"
33 "}\n";
34 NOT_IN_PRODUCT(FLAG_verbose_gc = true);
35 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
36 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
37
41 TransitionNativeToVM transition(thread);
42 GCTestHelper::CollectOldSpace();
43}
44
45#if !defined(PRODUCT)
46TEST_CASE(OldGC_Unsync) {
47 // Finalize any GC in progress as it is unsafe to change FLAG_marker_tasks
48 // when incremental marking is in progress.
49 {
50 TransitionNativeToVM transition(thread);
52 }
53 FLAG_marker_tasks = 0;
54
55 const char* kScriptChars =
56 "main() {\n"
57 " return [1, 2, 3];\n"
58 "}\n";
59 FLAG_verbose_gc = true;
60 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
61 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
62
66 TransitionNativeToVM transition(thread);
67 GCTestHelper::CollectOldSpace();
68}
69#endif // !defined(PRODUCT)
70
71TEST_CASE(LargeSweep) {
72 const char* kScriptChars =
73 "main() {\n"
74 " return List.filled(8 * 1024 * 1024, null);\n"
75 "}\n";
76 NOT_IN_PRODUCT(FLAG_verbose_gc = true);
77 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
79 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
80
84 {
85 TransitionNativeToVM transition(thread);
86 GCTestHelper::CollectOldSpace();
87 }
89 {
90 TransitionNativeToVM transition(thread);
91 GCTestHelper::CollectOldSpace();
92 }
93}
94
95#ifndef PRODUCT
96static ClassPtr GetClass(const Library& lib, const char* name) {
97 const Class& cls = Class::Handle(
98 lib.LookupClass(String::Handle(Symbols::New(Thread::Current(), name))));
99 EXPECT(!cls.IsNull()); // No ambiguity error expected.
100 return cls.ptr();
101}
102
103TEST_CASE(ClassHeapStats) {
104 const char* kScriptChars =
105 "class A {\n"
106 " var a;\n"
107 " var b;\n"
108 "}\n"
109 ""
110 "main() {\n"
111 " var x = new A();\n"
112 " return new A();\n"
113 "}\n";
114 Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, nullptr);
115 auto isolate_group = IsolateGroup::Current();
116 ClassTable* class_table = isolate_group->class_table();
117 {
118 // GC before main so allocations during the tests don't cause unexpected GC.
119 TransitionNativeToVM transition(thread);
121 }
123 Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, nullptr);
126 intptr_t cid;
127 {
128 TransitionNativeToVM transition(thread);
129 Library& lib = Library::Handle();
130 lib ^= Api::UnwrapHandle(h_lib);
131 EXPECT(!lib.IsNull());
132 const Class& cls = Class::Handle(GetClass(lib, "A"));
133 ASSERT(!cls.IsNull());
134 cid = cls.id();
135
136 {
137 // Verify preconditions: allocated twice in new space.
138 CountObjectsVisitor visitor(thread, class_table->NumCids());
139 HeapIterationScope iter(thread);
140 iter.IterateObjects(&visitor);
141 isolate_group->VisitWeakPersistentHandles(&visitor);
142 EXPECT_EQ(2, visitor.new_count_[cid]);
143 EXPECT_EQ(0, visitor.old_count_[cid]);
144 }
145
146 // Perform GC.
147 GCTestHelper::CollectNewSpace();
148
149 {
150 // Verify postconditions: Only one survived.
151 CountObjectsVisitor visitor(thread, class_table->NumCids());
152 HeapIterationScope iter(thread);
153 iter.IterateObjects(&visitor);
154 isolate_group->VisitWeakPersistentHandles(&visitor);
155 EXPECT_EQ(1, visitor.new_count_[cid]);
156 EXPECT_EQ(0, visitor.old_count_[cid]);
157 }
158
159 // Perform GC. The following is heavily dependent on the behaviour
160 // of the GC: Retained instance of A will be promoted.
161 GCTestHelper::CollectNewSpace();
162
163 {
164 // Verify postconditions: One promoted instance.
165 CountObjectsVisitor visitor(thread, class_table->NumCids());
166 HeapIterationScope iter(thread);
167 iter.IterateObjects(&visitor);
168 isolate_group->VisitWeakPersistentHandles(&visitor);
169 EXPECT_EQ(0, visitor.new_count_[cid]);
170 EXPECT_EQ(1, visitor.old_count_[cid]);
171 }
172
173 // Perform a GC on new space.
174 GCTestHelper::CollectNewSpace();
175
176 {
177 // Verify postconditions:
178 CountObjectsVisitor visitor(thread, class_table->NumCids());
179 HeapIterationScope iter(thread);
180 iter.IterateObjects(&visitor);
181 isolate_group->VisitWeakPersistentHandles(&visitor);
182 EXPECT_EQ(0, visitor.new_count_[cid]);
183 EXPECT_EQ(1, visitor.old_count_[cid]);
184 }
185
186 GCTestHelper::CollectOldSpace();
187
188 {
189 // Verify postconditions:
190 CountObjectsVisitor visitor(thread, class_table->NumCids());
191 HeapIterationScope iter(thread);
192 iter.IterateObjects(&visitor);
193 isolate_group->VisitWeakPersistentHandles(&visitor);
194 EXPECT_EQ(0, visitor.new_count_[cid]);
195 EXPECT_EQ(1, visitor.old_count_[cid]);
196 }
197 }
198 // Exit scope, freeing instance.
200 {
201 TransitionNativeToVM transition(thread);
202 // Perform GC.
203 GCTestHelper::CollectOldSpace();
204 {
205 // Verify postconditions:
206 CountObjectsVisitor visitor(thread, class_table->NumCids());
207 HeapIterationScope iter(thread);
208 iter.IterateObjects(&visitor);
209 isolate_group->VisitWeakPersistentHandles(&visitor);
210 EXPECT_EQ(0, visitor.new_count_[cid]);
211 EXPECT_EQ(0, visitor.old_count_[cid]);
212 }
213 }
214}
215#endif // !PRODUCT
216
217ISOLATE_UNIT_TEST_CASE(IterateReadOnly) {
218 const String& obj = String::Handle(String::New("x", Heap::kOld));
219
220 // It is not safe to make the heap read-only if marking or sweeping is in
221 // progress.
222 GCTestHelper::WaitForGCTasks();
223
224 Heap* heap = IsolateGroup::Current()->heap();
226 heap->WriteProtect(true);
228 heap->WriteProtect(false);
230}
231
232ISOLATE_UNIT_TEST_CASE(CollectAllGarbage_DeadOldToNew) {
233 Heap* heap = IsolateGroup::Current()->heap();
234
235 heap->CollectAllGarbage();
236 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
237 intptr_t size_before =
238 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
239
242 old.SetAt(0, neu);
243 old = Array::null();
244 neu = Array::null();
245
246 heap->CollectAllGarbage();
247 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
248
249 intptr_t size_after =
250 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
251
252 EXPECT_EQ(size_before, size_after);
253}
254
255ISOLATE_UNIT_TEST_CASE(CollectAllGarbage_DeadNewToOld) {
256 Heap* heap = IsolateGroup::Current()->heap();
257
258 heap->CollectAllGarbage();
259 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
260 intptr_t size_before =
261 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
262
265 neu.SetAt(0, old);
266 old = Array::null();
267 neu = Array::null();
268
269 heap->CollectAllGarbage();
270 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
271
272 intptr_t size_after =
273 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
274
275 EXPECT_EQ(size_before, size_after);
276}
277
278ISOLATE_UNIT_TEST_CASE(CollectAllGarbage_DeadGenCycle) {
279 Heap* heap = IsolateGroup::Current()->heap();
280
281 heap->CollectAllGarbage();
282 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
283 intptr_t size_before =
284 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
285
288 neu.SetAt(0, old);
289 old.SetAt(0, neu);
290 old = Array::null();
291 neu = Array::null();
292
293 heap->CollectAllGarbage();
294 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
295
296 intptr_t size_after =
297 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
298
299 EXPECT_EQ(size_before, size_after);
300}
301
302ISOLATE_UNIT_TEST_CASE(CollectAllGarbage_LiveNewToOld) {
303 Heap* heap = IsolateGroup::Current()->heap();
304
305 heap->CollectAllGarbage();
306 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
307 intptr_t size_before =
308 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
309
312 neu.SetAt(0, old);
313 old = Array::null();
314
315 heap->CollectAllGarbage();
316 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
317
318 intptr_t size_after =
319 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
320
321 EXPECT(size_before < size_after);
322}
323
324ISOLATE_UNIT_TEST_CASE(CollectAllGarbage_LiveOldToNew) {
325 Heap* heap = IsolateGroup::Current()->heap();
326
327 heap->CollectAllGarbage();
328 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
329 intptr_t size_before =
330 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
331
334 old.SetAt(0, neu);
335 neu = Array::null();
336
337 heap->CollectAllGarbage();
338 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
339
340 intptr_t size_after =
341 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
342
343 EXPECT(size_before < size_after);
344}
345
346ISOLATE_UNIT_TEST_CASE(CollectAllGarbage_LiveOldDeadNew) {
347 Heap* heap = IsolateGroup::Current()->heap();
348
349 heap->CollectAllGarbage();
350 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
351 intptr_t size_before =
352 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
353
356 neu = Array::null();
357 old.SetAt(0, old);
358
359 heap->CollectAllGarbage();
360 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
361
362 intptr_t size_after =
363 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
364
365 EXPECT(size_before < size_after);
366}
367
368ISOLATE_UNIT_TEST_CASE(CollectAllGarbage_LiveNewDeadOld) {
369 Heap* heap = IsolateGroup::Current()->heap();
370
371 heap->CollectAllGarbage();
372 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
373 intptr_t size_before =
374 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
375
378 old = Array::null();
379 neu.SetAt(0, neu);
380
381 heap->CollectAllGarbage();
382 heap->WaitForMarkerTasks(thread); // Finalize marking to get live size.
383
384 intptr_t size_after =
385 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
386
387 EXPECT(size_before < size_after);
388}
389
390ISOLATE_UNIT_TEST_CASE(CollectAllGarbage_LiveNewToOldChain) {
391 Heap* heap = IsolateGroup::Current()->heap();
392
393 heap->CollectAllGarbage();
394 intptr_t size_before =
395 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
396
400 old.SetAt(0, old2);
401 neu.SetAt(0, old);
402 old = Array::null();
403 old2 = Array::null();
404
405 heap->CollectAllGarbage();
406
407 intptr_t size_after =
408 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
409
410 EXPECT(size_before < size_after);
411}
412
413ISOLATE_UNIT_TEST_CASE(CollectAllGarbage_LiveOldToNewChain) {
414 Heap* heap = IsolateGroup::Current()->heap();
415
416 heap->CollectAllGarbage();
417 intptr_t size_before =
418 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
419
423 neu.SetAt(0, neu2);
424 old.SetAt(0, neu);
425 neu = Array::null();
426 neu2 = Array::null();
427
428 heap->CollectAllGarbage();
429
430 intptr_t size_after =
431 heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
432
433 EXPECT(size_before < size_after);
434}
435
436static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
437
438ISOLATE_UNIT_TEST_CASE(ExternalPromotion) {
439 auto isolate_group = IsolateGroup::Current();
440 Heap* heap = isolate_group->heap();
441
442 heap->CollectAllGarbage();
443 intptr_t size_before = kWordSize * (heap->new_space()->ExternalInWords() +
444 heap->old_space()->ExternalInWords());
445
447 Array& neu = Array::Handle();
448 for (intptr_t i = 0; i < 100; i++) {
449 neu = Array::New(1, Heap::kNew);
450 FinalizablePersistentHandle::New(isolate_group, neu, nullptr, NoopFinalizer,
451 1 * MB,
452 /*auto_delete=*/true);
453 old.SetAt(i, neu);
454 }
455
456 intptr_t size_middle = kWordSize * (heap->new_space()->ExternalInWords() +
457 heap->old_space()->ExternalInWords());
458 EXPECT_EQ(size_before + 100 * MB, size_middle);
459
460 old = Array::null();
461 neu = Array::null();
462
463 heap->CollectAllGarbage();
464
465 intptr_t size_after = kWordSize * (heap->new_space()->ExternalInWords() +
466 heap->old_space()->ExternalInWords());
467
468 EXPECT_EQ(size_before, size_after);
469}
470
471#if !defined(PRODUCT)
473 public:
474 static void Scavenge(Thread* thread) {
475 thread->heap()->CollectNewSpaceGarbage(thread, GCType::kScavenge,
477 }
478 static void MarkSweep(Thread* thread) {
479 thread->heap()->CollectOldSpaceGarbage(thread, GCType::kMarkSweep,
481 thread->heap()->WaitForMarkerTasks(thread);
482 thread->heap()->WaitForSweeperTasks(thread);
483 }
484};
485
487 public:
489 : msg_(CStringUniquePtr(nullptr)), owner_(owner) {}
490
491 const char* name() const { return "merge-isolates-heaps-handler"; }
492
494
495 MessageStatus HandleMessage(std::unique_ptr<Message> message) {
496 // Parse the message.
497 Object& response_obj = Object::Handle();
498 if (message->IsRaw()) {
499 response_obj = message->raw_obj();
500 } else if (message->IsPersistentHandle()) {
501 PersistentHandle* handle = message->persistent_handle();
502 // Object is in the receiving isolate's heap.
503 EXPECT(isolate()->group()->heap()->Contains(
504 UntaggedObject::ToAddr(handle->ptr())));
505 response_obj = handle->ptr();
507 } else {
509 response_obj = ReadMessage(thread, message.get());
510 }
511 if (response_obj.IsString()) {
512 String& response = String::Handle();
513 response ^= response_obj.ptr();
514 msg_.reset(Utils::StrDup(response.ToCString()));
515 } else {
516 ASSERT(response_obj.IsArray());
517 Array& response_array = Array::Handle();
518 response_array ^= response_obj.ptr();
519 ASSERT(response_array.Length() == 1);
521 response ^= response_array.At(0);
522 msg_.reset(Utils::StrDup(reinterpret_cast<char*>(response.DataAddr(0))));
523 }
524
525 return kOK;
526 }
527
528 const char* msg() const { return msg_.get(); }
529
530 virtual Isolate* isolate() const { return owner_; }
531
532 private:
533 CStringUniquePtr msg_;
534 Isolate* owner_;
535};
536
537VM_UNIT_TEST_CASE(CleanupBequestNeverReceived) {
538 const char* TEST_MESSAGE = "hello, world";
539 Dart_Isolate parent = TestCase::CreateTestIsolate("parent");
540 EXPECT_EQ(parent, Dart_CurrentIsolate());
541 {
543 Dart_Port port_id = PortMap::CreatePort(&handler);
544 EXPECT_EQ(PortMap::GetIsolate(port_id), Isolate::Current());
546
547 Dart_Isolate worker = TestCase::CreateTestIsolateInGroup("worker", parent);
548 EXPECT_EQ(worker, Dart_CurrentIsolate());
549 {
550 Thread* thread = Thread::Current();
551 TransitionNativeToVM transition(thread);
552 StackZone zone(thread);
553
554 String& string = String::Handle(String::New(TEST_MESSAGE));
555 PersistentHandle* handle =
557 handle->set_ptr(string.ptr());
558
559 reinterpret_cast<Isolate*>(worker)->bequeath(
560 std::unique_ptr<Bequest>(new Bequest(handle, port_id)));
561 }
562 }
564 Dart_EnterIsolate(parent);
566}
567
568VM_UNIT_TEST_CASE(ReceivesSendAndExitMessage) {
569 const char* TEST_MESSAGE = "hello, world";
570 Dart_Isolate parent = TestCase::CreateTestIsolate("parent");
571 EXPECT_EQ(parent, Dart_CurrentIsolate());
573 Dart_Port port_id = PortMap::CreatePort(&handler);
574 EXPECT_EQ(PortMap::GetIsolate(port_id), Isolate::Current());
576
577 Dart_Isolate worker = TestCase::CreateTestIsolateInGroup("worker", parent);
578 EXPECT_EQ(worker, Dart_CurrentIsolate());
579 {
580 Thread* thread = Thread::Current();
581 TransitionNativeToVM transition(thread);
582 StackZone zone(thread);
583
584 String& string = String::Handle(String::New(TEST_MESSAGE));
585
586 PersistentHandle* handle =
588 handle->set_ptr(string.ptr());
589
590 reinterpret_cast<Isolate*>(worker)->bequeath(
591 std::unique_ptr<Bequest>(new Bequest(handle, port_id)));
592 }
593
595 Dart_EnterIsolate(parent);
596 {
597 Thread* thread = Thread::Current();
598 TransitionNativeToVM transition(thread);
599 StackZone zone(thread);
600
601 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
602 }
603 EXPECT_STREQ(handler.msg(), TEST_MESSAGE);
605}
606
607ISOLATE_UNIT_TEST_CASE(ExternalAllocationStats) {
608 auto isolate_group = thread->isolate_group();
609 Heap* heap = isolate_group->heap();
610
612 Array& neu = Array::Handle();
613 for (intptr_t i = 0; i < 100; i++) {
614 neu = Array::New(1, Heap::kNew);
615 FinalizablePersistentHandle::New(isolate_group, neu, nullptr, NoopFinalizer,
616 1 * MB,
617 /*auto_delete=*/true);
618 old.SetAt(i, neu);
619
620 if ((i % 4) == 0) {
622 } else {
624 }
625
626 CountObjectsVisitor visitor(thread,
627 isolate_group->class_table()->NumCids());
628 HeapIterationScope iter(thread);
629 iter.IterateObjects(&visitor);
630 isolate_group->VisitWeakPersistentHandles(&visitor);
631 EXPECT_LE(visitor.old_external_size_[kArrayCid],
632 heap->old_space()->ExternalInWords() * kWordSize);
633 EXPECT_LE(visitor.new_external_size_[kArrayCid],
634 heap->new_space()->ExternalInWords() * kWordSize);
635 }
636}
637
638ISOLATE_UNIT_TEST_CASE(ExternalSizeLimit) {
639 // This test checks that the tracked total size of external data never exceeds
640 // the amount of memory on the system. To accomplish this, the test performs
641 // five calls to FinalizablePersistentHandle::New(), all supplying a size
642 // argument that is barely (16 bytes) less than a quarter of kMaxAddrSpaceMB.
643 // So, we expect the first four calls to succeed, and the fifth one to return
644 // nullptr.
645
646 auto isolate_group = thread->isolate_group();
647 Heap* heap = isolate_group->heap();
648
649 // We declare an array of only length 1 here to get around the limit of
650 // ExternalTypedData::MaxElements(kExternalTypedDataUint8ArrayCid). Below, we
651 // pretend that the length is longer when calling
652 // FinalizablePersistentHandle::New(), which is what updates the external size
653 // tracker.
654 const intptr_t data_length = 1;
655 uint8_t data[data_length] = {0};
656 const ExternalTypedData& external_typed_data_1 =
658 kExternalTypedDataUint8ArrayCid, data, data_length, Heap::kOld));
659 const ExternalTypedData& external_typed_data_2 =
661 kExternalTypedDataUint8ArrayCid, data, data_length, Heap::kOld));
662 const ExternalTypedData& external_typed_data_3 =
664 kExternalTypedDataUint8ArrayCid, data, data_length, Heap::kOld));
665 const ExternalTypedData& external_typed_data_4 =
667 kExternalTypedDataUint8ArrayCid, data, data_length, Heap::kOld));
668 const ExternalTypedData& external_typed_data_5 =
670 kExternalTypedDataUint8ArrayCid, data, data_length, Heap::kOld));
671
672 // A size that is less than a quarter of kMaxAddrSpaceMB is used because it
673 // needs to be less than or equal to std::numeric_limits<intptr_t>::max().
674 const intptr_t external_allocation_size =
675 (intptr_t{kMaxAddrSpaceMB / 4} << MBLog2) - 16;
677 isolate_group, external_typed_data_1, nullptr, NoopFinalizer,
678 external_allocation_size,
679 /*auto_delete=*/true));
680 EXPECT_LT(heap->old_space()->ExternalInWords(), kMaxAddrSpaceInWords);
681
683 isolate_group, external_typed_data_2, nullptr, NoopFinalizer,
684 external_allocation_size,
685 /*auto_delete=*/true));
686 EXPECT_LT(heap->old_space()->ExternalInWords(), kMaxAddrSpaceInWords);
687
689 isolate_group, external_typed_data_3, nullptr, NoopFinalizer,
690 external_allocation_size,
691 /*auto_delete=*/true));
692 EXPECT_LT(heap->old_space()->ExternalInWords(), kMaxAddrSpaceInWords);
693
695 isolate_group, external_typed_data_4, nullptr, NoopFinalizer,
696 external_allocation_size,
697 /*auto_delete=*/true));
698 EXPECT_LT(heap->old_space()->ExternalInWords(), kMaxAddrSpaceInWords);
699
701 isolate_group, external_typed_data_5, nullptr, NoopFinalizer,
702 external_allocation_size,
703 /*auto_delete=*/true));
704 // Check that the external size is indeed protected from overflowing.
705 EXPECT_LT(heap->old_space()->ExternalInWords(), kMaxAddrSpaceInWords);
706}
707#endif // !defined(PRODUCT)
708
709ISOLATE_UNIT_TEST_CASE(ArrayTruncationRaces) {
710 // Alternate between allocating new lists and truncating.
711 // For each list, the life cycle is
712 // 1) the list is allocated and filled with some elements
713 // 2) kNumLists other lists are allocated
714 // 3) the list's backing store is truncated; the list becomes unreachable
715 // 4) kNumLists other lists are allocated
716 // 5) the backing store becomes unreachable
717 // The goal is to cause truncation *during* concurrent mark or sweep, by
718 // truncating an array that had been alive for a while and will be visited by
719 // a GC triggering by the allocations in step 2.
720
721 intptr_t kMaxListLength = 100;
722 intptr_t kNumLists = 1000;
723 Array& lists = Array::Handle(Array::New(kNumLists));
724 Array& arrays = Array::Handle(Array::New(kNumLists));
725
727 Array& array = Array::Handle();
728 Object& element = Object::Handle();
729
730 for (intptr_t i = 0; i < kNumLists; i++) {
732 intptr_t length = i % kMaxListLength;
733 for (intptr_t j = 0; j < length; j++) {
734 list.Add(element, Heap::kNew);
735 }
736 lists.SetAt(i, list);
737 }
738
739 intptr_t kTruncations = 100000;
740 for (intptr_t i = 0; i < kTruncations; i++) {
741 list ^= lists.At(i % kNumLists);
742 array = Array::MakeFixedLength(list);
743 arrays.SetAt(i % kNumLists, array);
744
746 intptr_t length = i % kMaxListLength;
747 for (intptr_t j = 0; j < length; j++) {
748 list.Add(element, Heap::kOld);
749 }
750 lists.SetAt(i % kNumLists, list);
751 }
752}
753
754// See https://github.com/dart-lang/sdk/issues/54495
755ISOLATE_UNIT_TEST_CASE(ArrayTruncationPadding) {
756 GrowableObjectArray& retain =
758 Array& array = Array::Handle();
759
760 for (intptr_t big = 0; big < 256; big++) {
761 for (intptr_t small = 0; small < big; small++) {
762 array = Array::New(big);
763
764 // Fill the alignment gap with invalid pointers.
766 for (intptr_t offset = Array::UnroundedSize(big);
767 offset < Array::InstanceSize(big); offset += sizeof(uword)) {
768 *reinterpret_cast<uword*>(addr + offset) = kHeapObjectTag;
769 }
770
771 array.Truncate(small);
772 retain.Add(array);
773 }
774 }
775
776 IsolateGroup::Current()->heap()->Verify("truncation padding");
777}
778
780 public:
782 Monitor* monitor,
783 intptr_t* done_count)
784 : isolate_group_(isolate_group),
785 monitor_(monitor),
786 done_count_(done_count) {}
787
788 virtual void Run() {
789 const bool kBypassSafepoint = false;
791 kBypassSafepoint);
792 {
793 Thread* thread = Thread::Current();
794 StackZone stack_zone(thread);
795
796 GrowableObjectArray& accumulate =
798 Object& element = Object::Handle();
799 for (intptr_t i = 0; i < 1000; i++) {
800 // Lots of entering and leaving ForceGrowth scopes. Previously, this
801 // would have been data races on the per-Heap force-growth flag.
802 {
803 ForceGrowthScope force_growth(thread);
804 GrowableObjectArrayPtr unsafe_accumulate = accumulate.ptr();
805 element = Array::New(0);
806 accumulate = unsafe_accumulate;
807 }
808 accumulate.Add(element);
809 }
810 }
811 Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
812 // Notify the main thread that this thread has exited.
813 {
814 MonitorLocker ml(monitor_);
815 *done_count_ += 1;
816 ml.Notify();
817 }
818 }
819
820 private:
821 IsolateGroup* isolate_group_;
822 Monitor* monitor_;
823 intptr_t* done_count_;
824};
825
826ISOLATE_UNIT_TEST_CASE(ConcurrentForceGrowthScope) {
827 intptr_t task_count = 8;
828 Monitor monitor;
829 intptr_t done_count = 0;
830
831 for (intptr_t i = 0; i < task_count; i++) {
833 thread->isolate_group(), &monitor, &done_count);
834 }
835
836 {
837 MonitorLocker ml(&monitor);
838 while (done_count < task_count) {
839 ml.WaitWithSafepointCheck(thread);
840 }
841 }
842}
843
845 // Weaklings are prevented from referencing Smis by the public Dart library
846 // interface, but the VM internally can do this and the implementation should
847 // just handle it. Immediate objects are effectively immortal.
848
849 WeakProperty& new_ephemeron =
851 WeakProperty& old_ephemeron =
853 WeakReference& new_weakref =
855 WeakReference& old_weakref =
859 FinalizerEntry& new_finalizer = FinalizerEntry::Handle(
861 FinalizerEntry& old_finalizer = FinalizerEntry::Handle(
863
864 {
865 HANDLESCOPE(thread);
866 Smi& smi = Smi::Handle(Smi::New(42));
867 new_ephemeron.set_key(smi);
868 old_ephemeron.set_key(smi);
869 new_weakref.set_target(smi);
870 old_weakref.set_target(smi);
871 new_weakarray.SetAt(0, smi);
872 old_weakarray.SetAt(0, smi);
873 new_finalizer.set_value(smi);
874 old_finalizer.set_value(smi);
875 }
876
877 GCTestHelper::CollectNewSpace();
879
880 EXPECT(new_ephemeron.key() == Smi::New(42));
881 EXPECT(old_ephemeron.key() == Smi::New(42));
882 EXPECT(new_weakref.target() == Smi::New(42));
883 EXPECT(old_weakref.target() == Smi::New(42));
884 EXPECT(new_weakarray.At(0) == Smi::New(42));
885 EXPECT(old_weakarray.At(0) == Smi::New(42));
886 EXPECT(new_finalizer.value() == Smi::New(42));
887 EXPECT(old_finalizer.value() == Smi::New(42));
888}
889
894};
895
896static void WeakProperty_Generations(Generation property_space,
897 Generation key_space,
898 Generation value_space,
899 bool cleared_after_minor,
900 bool cleared_after_major,
901 bool cleared_after_all) {
904 {
906 switch (property_space) {
907 case kNew:
908 property = WeakProperty::New(Heap::kNew);
909 break;
910 case kOld:
911 property = WeakProperty::New(Heap::kOld);
912 break;
913 case kImm:
914 UNREACHABLE();
915 }
916
918 switch (key_space) {
919 case kNew:
921 break;
922 case kOld:
924 break;
925 case kImm:
926 key = Smi::New(42);
927 break;
928 }
929
931 switch (value_space) {
932 case kNew:
934 break;
935 case kOld:
937 break;
938 case kImm:
939 value = Smi::New(84);
940 break;
941 }
942
943 property.set_key(key);
944 property.set_value(value);
945 }
946
947 OS::PrintErr("%d %d %d\n", property_space, key_space, value_space);
948
949 GCTestHelper::CollectNewSpace();
950 if (cleared_after_minor) {
951 EXPECT(property.key() == Object::null());
952 EXPECT(property.value() == Object::null());
953 } else {
954 EXPECT(property.key() != Object::null());
955 EXPECT(property.value() != Object::null());
956 }
957
958 GCTestHelper::CollectOldSpace();
959 if (cleared_after_major) {
960 EXPECT(property.key() == Object::null());
961 EXPECT(property.value() == Object::null());
962 } else {
963 EXPECT(property.key() != Object::null());
964 EXPECT(property.value() != Object::null());
965 }
966
968 if (cleared_after_all) {
969 EXPECT(property.key() == Object::null());
970 EXPECT(property.value() == Object::null());
971 } else {
972 EXPECT(property.key() != Object::null());
973 EXPECT(property.value() != Object::null());
974 }
975}
976
978 FLAG_early_tenuring_threshold = 100; // I.e., off.
979
980 WeakProperty_Generations(kNew, kNew, kNew, true, true, true);
981 WeakProperty_Generations(kNew, kNew, kOld, true, true, true);
982 WeakProperty_Generations(kNew, kNew, kImm, true, true, true);
983 WeakProperty_Generations(kNew, kOld, kNew, false, true, true);
984 WeakProperty_Generations(kNew, kOld, kOld, false, true, true);
985 WeakProperty_Generations(kNew, kOld, kImm, false, true, true);
986 WeakProperty_Generations(kNew, kImm, kNew, false, false, false);
987 WeakProperty_Generations(kNew, kImm, kOld, false, false, false);
988 WeakProperty_Generations(kNew, kImm, kImm, false, false, false);
989 WeakProperty_Generations(kOld, kNew, kNew, true, true, true);
990 WeakProperty_Generations(kOld, kNew, kOld, true, true, true);
991 WeakProperty_Generations(kOld, kNew, kImm, true, true, true);
992 WeakProperty_Generations(kOld, kOld, kNew, false, true, true);
993 WeakProperty_Generations(kOld, kOld, kOld, false, true, true);
994 WeakProperty_Generations(kOld, kOld, kImm, false, true, true);
995 WeakProperty_Generations(kOld, kImm, kNew, false, false, false);
996 WeakProperty_Generations(kOld, kImm, kOld, false, false, false);
997 WeakProperty_Generations(kOld, kImm, kImm, false, false, false);
998}
999
1000static void WeakReference_Generations(Generation reference_space,
1001 Generation target_space,
1002 bool cleared_after_minor,
1003 bool cleared_after_major,
1004 bool cleared_after_all) {
1005 WeakReference& reference = WeakReference::Handle();
1007 {
1009 switch (reference_space) {
1010 case kNew:
1011 reference = WeakReference::New(Heap::kNew);
1012 break;
1013 case kOld:
1014 reference = WeakReference::New(Heap::kOld);
1015 break;
1016 case kImm:
1017 UNREACHABLE();
1018 }
1019
1021 switch (target_space) {
1022 case kNew:
1024 break;
1025 case kOld:
1027 break;
1028 case kImm:
1029 target = Smi::New(42);
1030 break;
1031 }
1032
1033 reference.set_target(target);
1034 }
1035
1036 OS::PrintErr("%d %d\n", reference_space, target_space);
1037
1038 GCTestHelper::CollectNewSpace();
1039 if (cleared_after_minor) {
1040 EXPECT(reference.target() == Object::null());
1041 } else {
1042 EXPECT(reference.target() != Object::null());
1043 }
1044
1045 GCTestHelper::CollectOldSpace();
1046 if (cleared_after_major) {
1047 EXPECT(reference.target() == Object::null());
1048 } else {
1049 EXPECT(reference.target() != Object::null());
1050 }
1051
1053 if (cleared_after_all) {
1054 EXPECT(reference.target() == Object::null());
1055 } else {
1056 EXPECT(reference.target() != Object::null());
1057 }
1058}
1059
1061 FLAG_early_tenuring_threshold = 100; // I.e., off.
1062
1063 WeakReference_Generations(kNew, kNew, true, true, true);
1064 WeakReference_Generations(kNew, kOld, false, true, true);
1065 WeakReference_Generations(kNew, kImm, false, false, false);
1066 WeakReference_Generations(kOld, kNew, true, true, true);
1067 WeakReference_Generations(kOld, kOld, false, true, true);
1068 WeakReference_Generations(kOld, kImm, false, false, false);
1069}
1070
1071static void WeakArray_Generations(intptr_t length,
1072 Generation array_space,
1073 Generation element_space,
1074 bool cleared_after_minor,
1075 bool cleared_after_major,
1076 bool cleared_after_all) {
1077 WeakArray& array = WeakArray::Handle();
1079 {
1081 switch (array_space) {
1082 case kNew:
1084 break;
1085 case kOld:
1087 break;
1088 case kImm:
1089 UNREACHABLE();
1090 }
1091
1092 Object& element = Object::Handle();
1093 switch (element_space) {
1094 case kNew:
1095 element = OneByteString::New("element", Heap::kNew);
1096 break;
1097 case kOld:
1098 element = OneByteString::New("element", Heap::kOld);
1099 break;
1100 case kImm:
1101 element = Smi::New(42);
1102 break;
1103 }
1104
1105 array.SetAt(length - 1, element);
1106 }
1107
1108 OS::PrintErr("%d %d\n", array_space, element_space);
1109
1110 GCTestHelper::CollectNewSpace();
1111 if (cleared_after_minor) {
1112 EXPECT(array.At(length - 1) == Object::null());
1113 } else {
1114 EXPECT(array.At(length - 1) != Object::null());
1115 }
1116
1117 GCTestHelper::CollectOldSpace();
1118 if (cleared_after_major) {
1119 EXPECT(array.At(length - 1) == Object::null());
1120 } else {
1121 EXPECT(array.At(length - 1) != Object::null());
1122 }
1123
1125 if (cleared_after_all) {
1126 EXPECT(array.At(length - 1) == Object::null());
1127 } else {
1128 EXPECT(array.At(length - 1) != Object::null());
1129 }
1130}
1131
1133 FLAG_early_tenuring_threshold = 100; // I.e., off.
1134
1135 intptr_t length = 1;
1136 WeakArray_Generations(length, kNew, kNew, true, true, true);
1137 WeakArray_Generations(length, kNew, kOld, false, true, true);
1138 WeakArray_Generations(length, kNew, kImm, false, false, false);
1139 WeakArray_Generations(length, kOld, kNew, true, true, true);
1140 WeakArray_Generations(length, kOld, kOld, false, true, true);
1141 WeakArray_Generations(length, kOld, kImm, false, false, false);
1142}
1143
1144ISOLATE_UNIT_TEST_CASE(WeakArray_Large_Generations) {
1145 FLAG_early_tenuring_threshold = 100; // I.e., off.
1146
1148 WeakArray_Generations(length, kNew, kNew, true, true, true);
1149 WeakArray_Generations(length, kNew, kOld, false, true, true);
1150 WeakArray_Generations(length, kNew, kImm, false, false, false);
1151 WeakArray_Generations(length, kOld, kNew, true, true, true);
1152 WeakArray_Generations(length, kOld, kOld, false, true, true);
1153 WeakArray_Generations(length, kOld, kImm, false, false, false);
1154}
1155
1157 Generation value_space,
1158 bool cleared_after_minor,
1159 bool cleared_after_major,
1160 bool cleared_after_all) {
1163 {
1165 switch (entry_space) {
1166 case kNew:
1168 break;
1169 case kOld:
1171 break;
1172 case kImm:
1173 UNREACHABLE();
1174 }
1175
1177 switch (value_space) {
1178 case kNew:
1180 break;
1181 case kOld:
1183 break;
1184 case kImm:
1185 value = Smi::New(42);
1186 break;
1187 }
1188
1189 entry.set_value(value);
1190 }
1191
1192 OS::PrintErr("%d %d\n", entry_space, value_space);
1193
1194 GCTestHelper::CollectNewSpace();
1195 if (cleared_after_minor) {
1196 EXPECT(entry.value() == Object::null());
1197 } else {
1198 EXPECT(entry.value() != Object::null());
1199 }
1200
1201 GCTestHelper::CollectOldSpace();
1202 if (cleared_after_major) {
1203 EXPECT(entry.value() == Object::null());
1204 } else {
1205 EXPECT(entry.value() != Object::null());
1206 }
1207
1209 if (cleared_after_all) {
1210 EXPECT(entry.value() == Object::null());
1211 } else {
1212 EXPECT(entry.value() != Object::null());
1213 }
1214}
1215
1217 FLAG_early_tenuring_threshold = 100; // I.e., off.
1218
1219 FinalizerEntry_Generations(kNew, kNew, true, true, true);
1220 FinalizerEntry_Generations(kNew, kOld, false, true, true);
1221 FinalizerEntry_Generations(kNew, kImm, false, false, false);
1222 FinalizerEntry_Generations(kOld, kNew, true, true, true);
1223 FinalizerEntry_Generations(kOld, kOld, false, true, true);
1224 FinalizerEntry_Generations(kOld, kImm, false, false, false);
1225}
1226
1227#if !defined(PRODUCT) && defined(DART_HOST_OS_LINUX)
1228ISOLATE_UNIT_TEST_CASE(SweepDontNeed) {
1229 auto gc_with_fragmentation = [&] {
1230 HANDLESCOPE(thread);
1231
1233 const intptr_t num_elements = 100 * MB / Array::InstanceSize(128);
1234 Array& list = Array::Handle();
1235 {
1236 HANDLESCOPE(thread);
1237 list = Array::New(num_elements);
1238 Array& element = Array::Handle();
1239 for (intptr_t i = 0; i < num_elements; i++) {
1240 element = Array::New(128);
1241 list.SetAt(i, element);
1242 }
1243 }
1244
1246 GCTestHelper::WaitForGCTasks();
1248 const intptr_t before = Service::CurrentRSS();
1249 EXPECT(before > 0); // Or RSS hook is not installed.
1250
1251 for (intptr_t i = 0; i < num_elements; i++) {
1252 // Let there be one survivor every 150 KB. Bigger than the largest virtual
1253 // memory page size (64 KB on ARM64 Linux).
1254 intptr_t m = 150 * KB / Array::InstanceSize(128);
1255 if ((i % m) != 0) {
1256 list.SetAt(i, Object::null_object());
1257 }
1258 }
1259
1261 GCTestHelper::WaitForGCTasks();
1263 const intptr_t after = Service::CurrentRSS();
1264 EXPECT(after > 0); // Or RSS hook is not installed.
1265
1266 const intptr_t delta = after - before;
1267 OS::PrintErr("%" Pd " -> %" Pd " (%" Pd ")\n", before, after, delta);
1268 return delta;
1269 };
1270
1271 FLAG_dontneed_on_sweep = false;
1272 const intptr_t delta_normal = gc_with_fragmentation();
1273 // EXPECT(delta_normal == 0); Roughly, but there may be noise.
1274
1275 FLAG_dontneed_on_sweep = true;
1276 const intptr_t delta_dontneed = gc_with_fragmentation();
1277 // Free at least half. Various with noise and virtual memory page size.
1278 EXPECT(delta_dontneed < -50 * MB);
1279
1280 EXPECT(delta_dontneed < delta_normal); // More negative.
1281}
1282#endif // !defined(PRODUCT) && !defined(DART_HOST_OS_LINUX)
1283
1284static void TestCardRememberedArray(bool immutable, bool compact) {
1285 constexpr intptr_t kNumElements = kNewAllocatableSize / kCompressedWordSize;
1286 Array& array = Array::Handle(Array::New(kNumElements));
1287 EXPECT(array.ptr()->untag()->IsCardRemembered());
1288 EXPECT(Page::Of(array.ptr())->is_large());
1289
1290 {
1292 Object& element = Object::Handle();
1293 for (intptr_t i = 0; i < kNumElements; i++) {
1294 element = Double::New(i, Heap::kNew); // Garbage
1295 element = Double::New(i, Heap::kNew);
1296 array.SetAt(i, element);
1297 }
1298 if (immutable) {
1299 array.MakeImmutable();
1300 }
1301 }
1302
1304 GCTestHelper::WaitForGCTasks();
1305
1306 {
1308 Object& element = Object::Handle();
1309 for (intptr_t i = 0; i < kNumElements; i++) {
1310 element = array.At(i);
1311 EXPECT(element.IsDouble());
1312 EXPECT(Double::Cast(element).value() == i);
1313 }
1314 }
1315}
1316
1317static void TestCardRememberedWeakArray(bool compact) {
1318 constexpr intptr_t kNumElements = kNewAllocatableSize / kCompressedWordSize;
1319 WeakArray& weak = WeakArray::Handle(WeakArray::New(kNumElements));
1320 EXPECT(!weak.ptr()->untag()->IsCardRemembered());
1321 EXPECT(Page::Of(weak.ptr())->is_large());
1322 Array& strong = Array::Handle(Array::New(kNumElements));
1323
1324 {
1326 Object& element = Object::Handle();
1327 for (intptr_t i = 0; i < kNumElements; i++) {
1328 element = Double::New(i, Heap::kNew); // Garbage
1329 element = Double::New(i, Heap::kNew);
1330 weak.SetAt(i, element);
1331 if ((i % 3) == 0) {
1332 strong.SetAt(i, element);
1333 }
1334 }
1335 }
1336
1338 GCTestHelper::WaitForGCTasks();
1339
1340 {
1342 Object& element = Object::Handle();
1343 for (intptr_t i = 0; i < kNumElements; i++) {
1344 element = weak.At(i);
1345 if ((i % 3) == 0) {
1346 EXPECT(element.IsDouble());
1347 EXPECT(Double::Cast(element).value() == i);
1348 } else {
1349 EXPECT(element.IsNull());
1350 }
1351 }
1352 }
1353}
1354
1355ISOLATE_UNIT_TEST_CASE(CardRememberedArray) {
1356 TestCardRememberedArray(true, true);
1357 TestCardRememberedArray(true, false);
1358}
1359
1360ISOLATE_UNIT_TEST_CASE(CardRememberedImmutableArray) {
1361 TestCardRememberedArray(false, true);
1362 TestCardRememberedArray(false, false);
1363}
1364
1365ISOLATE_UNIT_TEST_CASE(CardRememberedWeakArray) {
1368}
1369
1370} // namespace dart
#define EXPECT(type, expectedAlignment, expectedSize)
#define UNREACHABLE()
Definition: assert.h:248
PersistentHandle * AllocatePersistentHandle()
void FreePersistentHandle(PersistentHandle *ref)
static ObjectPtr UnwrapHandle(Dart_Handle object)
static intptr_t InstanceSize()
Definition: object.h:10936
static ArrayPtr New(intptr_t len, Heap::Space space=Heap::kNew)
Definition: object.h:10959
void Truncate(intptr_t new_length) const
Definition: object.cc:24894
void MakeImmutable() const
Definition: object.cc:24837
ObjectPtr At(intptr_t index) const
Definition: object.h:10875
intptr_t Length() const
Definition: object.h:10829
static ArrayPtr MakeFixedLength(const GrowableObjectArray &growable_array, bool unique=false)
Definition: object.cc:24935
void SetAt(intptr_t index, const Object &value) const
Definition: object.h:10880
intptr_t NumCids() const
Definition: class_table.h:447
intptr_t id() const
Definition: object.h:1233
ConcurrentForceGrowthScopeTask(IsolateGroup *isolate_group, Monitor *monitor, intptr_t *done_count)
Definition: heap_test.cc:781
static ThreadPool * thread_pool()
Definition: dart.h:73
static DoublePtr New(double d, Heap::Space space=Heap::kNew)
Definition: object.cc:23402
static ExternalTypedDataPtr New(intptr_t class_id, uint8_t *data, intptr_t len, Heap::Space space=Heap::kNew, bool perform_eager_msan_initialization_check=true)
Definition: object.cc:25626
static FinalizablePersistentHandle * New(IsolateGroup *isolate_group, const Object &object, void *peer, Dart_HandleFinalizer callback, intptr_t external_size, bool auto_delete)
void set_value(const Object &value) const
Definition: object.h:12971
ObjectPtr value() const
Definition: object.h:12970
static FinalizerEntryPtr New(const FinalizerBase &finalizer, Heap::Space space=Heap::kNew)
Definition: object.cc:26862
void Add(const Object &value, Heap::Space space=Heap::kNew) const
Definition: object.cc:24991
static GrowableObjectArrayPtr New(Heap::Space space=Heap::kNew)
Definition: object.h:11144
void IterateObjects(ObjectVisitor *visitor) const
Definition: heap.cc:335
static void MarkSweep(Thread *thread)
Definition: heap_test.cc:478
static void Scavenge(Thread *thread)
Definition: heap_test.cc:474
@ kNew
Definition: heap.h:38
@ kOld
Definition: heap.h:39
Scavenger * new_space()
Definition: heap.h:62
void WriteProtect(bool read_only)
Definition: heap.cc:698
PageSpace * old_space()
Definition: heap.h:63
void WaitForMarkerTasks(Thread *thread)
Definition: heap.cc:656
bool Verify(const char *msg, MarkExpectation mark_expectation=kForbidMarked)
Definition: heap.cc:771
void CollectAllGarbage(GCReason reason=GCReason::kFull, bool compact=false)
Definition: heap.cc:573
void WaitForSweeperTasks(Thread *thread)
Definition: heap.cc:671
bool Contains(uword addr) const
Definition: heap.cc:239
static intptr_t UnroundedSize()
Definition: object.h:8336
Heap * heap() const
Definition: isolate.h:296
static IsolateGroup * Current()
Definition: isolate.h:539
ApiState * api_state() const
Definition: isolate.h:700
static Isolate * Current()
Definition: isolate.h:986
IsolateGroup * group() const
Definition: isolate.h:1037
Thread * thread() const
MessageStatus HandleNextMessage()
Monitor::WaitResult WaitWithSafepointCheck(Thread *thread, int64_t millis=Monitor::kNoTimeout)
Definition: lockers.cc:12
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
UntaggedObject * untag() const
static ObjectPtr null()
Definition: object.h:433
ObjectPtr ptr() const
Definition: object.h:332
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static OneByteStringPtr New(intptr_t len, Heap::Space space)
Definition: object.cc:24368
intptr_t UsedInWords() const
Definition: pages.h:194
intptr_t ExternalInWords() const
Definition: pages.h:212
static Page * Of(ObjectPtr obj)
Definition: page.h:162
bool is_large() const
Definition: page.h:78
static void ClearCache()
Definition: page.cc:36
void set_ptr(ObjectPtr ref)
ObjectPtr ptr() const
static Isolate * GetIsolate(Dart_Port id)
Definition: port.cc:181
static void ClosePorts(MessageHandler *handler)
Definition: port.cc:128
static Dart_Port CreatePort(MessageHandler *handler)
Definition: port.cc:55
intptr_t ExternalInWords() const
Definition: scavenger.h:168
intptr_t UsedInWords() const
Definition: scavenger.h:160
virtual Isolate * isolate() const
Definition: heap_test.cc:530
MessageStatus HandleMessage(std::unique_ptr< Message > message)
Definition: heap_test.cc:495
const char * name() const
Definition: heap_test.cc:491
const char * msg() const
Definition: heap_test.cc:528
SendAndExitMessagesHandler(Isolate *owner)
Definition: heap_test.cc:488
static int64_t CurrentRSS()
Definition: service.cc:1451
static SmiPtr New(intptr_t value)
Definition: object.h:10006
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
static const char * ToCString(Thread *thread, StringPtr ptr)
Definition: object.cc:24126
static StringPtr New(Thread *thread, const char *cstr)
Definition: symbols.h:723
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition: unit_test.cc:436
static Dart_Isolate CreateTestIsolateInGroup(const char *name, Dart_Isolate parent, void *group_data=nullptr, void *isolate_data=nullptr)
Definition: unit_test.cc:163
static Dart_Isolate CreateTestIsolate(const char *name=nullptr, void *isolate_group_data=nullptr, void *isolate_data=nullptr)
Definition: unit_test.cc:140
bool Run(Args &&... args)
Definition: thread_pool.h:45
@ kUnknownTask
Definition: thread.h:346
static Thread * Current()
Definition: thread.h:362
Heap * heap() const
Definition: thread.cc:943
static void ExitIsolateGroupAsHelper(bool bypass_safepoint)
Definition: thread.cc:499
static bool EnterIsolateGroupAsHelper(IsolateGroup *isolate_group, TaskKind kind, bool bypass_safepoint)
Definition: thread.cc:481
void * DataAddr(intptr_t byte_offset) const
Definition: object.h:11571
bool IsCardRemembered() const
Definition: raw_object.h:385
static uword ToAddr(const UntaggedObject *raw_obj)
Definition: raw_object.h:522
static char * StrDup(const char *s)
void SetAt(intptr_t index, const Object &value) const
Definition: object.h:6723
ObjectPtr At(intptr_t index) const
Definition: object.h:6722
static WeakArrayPtr New(intptr_t length, Heap::Space space=Heap::kNew)
Definition: object.cc:17533
static WeakPropertyPtr New(Heap::Space space=Heap::kNew)
Definition: object.cc:26756
void set_key(const Object &key) const
Definition: object.h:12921
ObjectPtr key() const
Definition: object.h:12920
ObjectPtr target() const
Definition: object.h:12944
static WeakReferencePtr New(Heap::Space space=Heap::kNew)
Definition: object.cc:26766
void set_target(const Object &target) const
Definition: object.h:12945
int64_t Dart_Port
Definition: dart_api.h:1525
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
struct _Dart_Isolate * Dart_Isolate
Definition: dart_api.h:88
#define ASSERT(E)
uint8_t value
GAsyncResult * result
uint32_t * target
#define HANDLESCOPE(thread)
Definition: handles.h:321
size_t length
Win32Message message
bool Contains(const Container &container, const Value &value)
Definition: dart_vm.cc:33
constexpr intptr_t MB
Definition: globals.h:530
ObjectPtr ReadMessage(Thread *thread, Message *message)
static void WeakArray_Generations(intptr_t length, Generation array_space, Generation element_space, bool cleared_after_minor, bool cleared_after_major, bool cleared_after_all)
Definition: heap_test.cc:1071
DART_EXPORT void Dart_EnterScope()
const char *const name
static void WeakReference_Generations(Generation reference_space, Generation target_space, bool cleared_after_minor, bool cleared_after_major, bool cleared_after_all)
Definition: heap_test.cc:1000
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate)
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
Generation
Definition: heap_test.cc:890
@ kNew
Definition: heap_test.cc:891
@ kImm
Definition: heap_test.cc:893
@ kOld
Definition: heap_test.cc:892
constexpr intptr_t MBLog2
Definition: globals.h:529
constexpr intptr_t KB
Definition: globals.h:528
uintptr_t uword
Definition: globals.h:501
DART_EXPORT Dart_Isolate Dart_CurrentIsolate()
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
DART_EXPORT void Dart_ExitIsolate()
ClassPtr GetClass(const Library &lib, const char *name)
const intptr_t cid
static constexpr intptr_t kCompressedWordSize
Definition: globals.h:42
TEST_CASE(DirectoryCurrent)
Dart_Handle NewString(const char *str)
static void TestCardRememberedWeakArray(bool compact)
Definition: heap_test.cc:1317
DART_EXPORT void Dart_ExitScope()
static void NoopFinalizer(void *isolate_callback_data, void *peer)
Definition: heap_test.cc:436
constexpr intptr_t kWordSize
Definition: globals.h:509
static void WeakProperty_Generations(Generation property_space, Generation key_space, Generation value_space, bool cleared_after_minor, bool cleared_after_major, bool cleared_after_all)
Definition: heap_test.cc:896
DART_EXPORT bool Dart_IsList(Dart_Handle object)
static void CollectAllGarbage(Thread *thread, JSONStream *js)
Definition: service.cc:4559
DART_EXPORT bool Dart_IsNull(Dart_Handle object)
static int8_t data[kExtLength]
static void FinalizerEntry_Generations(Generation entry_space, Generation value_space, bool cleared_after_minor, bool cleared_after_major, bool cleared_after_all)
Definition: heap_test.cc:1156
static void TestCardRememberedArray(bool immutable, bool compact)
Definition: heap_test.cc:1284
bool IsAllocatableViaFreeLists(intptr_t size)
Definition: spaces.h:60
DART_EXPORT void Dart_ShutdownIsolate()
NOT_IN_PRODUCT(LibraryPtr ReloadTestScript(const char *script))
@ kHeapObjectTag
const intptr_t kMaxAddrSpaceInWords
Definition: globals.h:50
static constexpr intptr_t kNewAllocatableSize
Definition: spaces.h:54
const intptr_t kMaxAddrSpaceMB
Definition: globals.h:49
DECLARE_FLAG(bool, show_invisible_frames)
VM_UNIT_TEST_CASE(DirectoryCurrentNoScope)
#define Pd
Definition: globals.h:408
SeparatedVector2 offset
#define EXPECT_VALID(handle)
Definition: unit_test.h:643