1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #include "platform/Task.h" 34 #include "platform/heap/Handle.h" 35 #include "platform/heap/Heap.h" 36 #include "platform/heap/HeapLinkedStack.h" 37 #include "platform/heap/HeapTerminatedArrayBuilder.h" 38 #include "platform/heap/ThreadState.h" 39 #include "platform/heap/Visitor.h" 40 #include "public/platform/Platform.h" 41 #include "wtf/HashTraits.h" 42 #include "wtf/LinkedHashSet.h" 43 44 #include <gtest/gtest.h> 45 46 namespace blink { 47 48 class IntWrapper : public GarbageCollectedFinalized<IntWrapper> { 49 public: 50 static IntWrapper* create(int x) 51 { 52 return new IntWrapper(x); 53 } 54 55 virtual ~IntWrapper() 56 { 57 ++s_destructorCalls; 58 } 59 60 static int s_destructorCalls; 61 static void trace(Visitor*) { } 62 63 int value() const { return m_x; } 64 65 bool operator==(const IntWrapper& other) const { return other.value() == value(); } 66 67 unsigned hash() { return IntHash<int>::hash(m_x); } 68 69 IntWrapper(int x) : m_x(x) { } 70 71 private: 72 IntWrapper(); 73 int m_x; 74 }; 75 76 USED_FROM_MULTIPLE_THREADS(IntWrapper); 77 78 class ThreadMarker { 79 public: 80 ThreadMarker() : m_creatingThread(reinterpret_cast<ThreadState*>(0)), m_num(0) { } 81 ThreadMarker(unsigned i) : m_creatingThread(ThreadState::current()), m_num(i) { } 82 ThreadMarker(WTF::HashTableDeletedValueType deleted) : m_creatingThread(reinterpret_cast<ThreadState*>(-1)), m_num(0) { } 83 ~ThreadMarker() 84 { 85 EXPECT_TRUE((m_creatingThread == ThreadState::current()) 86 || (m_creatingThread == reinterpret_cast<ThreadState*>(0)) 87 || (m_creatingThread == reinterpret_cast<ThreadState*>(-1))); 88 } 89 bool isHashTableDeletedValue() const { return m_creatingThread == reinterpret_cast<ThreadState*>(-1); } 90 bool operator==(const ThreadMarker& other) const { return other.m_creatingThread == m_creatingThread && other.m_num == m_num; } 91 ThreadState* m_creatingThread; 92 unsigned m_num; 93 }; 94 95 struct ThreadMarkerHash { 96 static unsigned hash(const ThreadMarker& key) 97 { 98 return static_cast<unsigned>(reinterpret_cast<uintptr_t>(key.m_creatingThread) + key.m_num); 99 } 100 101 static bool equal(const ThreadMarker& a, const ThreadMarker& b) 102 { 103 return a == b; 104 } 105 106 static const bool safeToCompareToEmptyOrDeleted = false; 107 }; 108 109 typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeakPair; 110 111 struct PairWithWeakHandling : public StrongWeakPair { 112 ALLOW_ONLY_INLINE_ALLOCATION(); 113 114 public: 115 // Regular constructor. 116 PairWithWeakHandling(IntWrapper* one, IntWrapper* two) 117 : StrongWeakPair(one, two) 118 { 119 ASSERT(one); // We use null first field to indicate empty slots in the hash table. 120 } 121 122 // The HashTable (via the HashTrait) calls this constructor with a 123 // placement new to mark slots in the hash table as being deleted. We will 124 // never call trace or the destructor on these slots. We mark ourselves deleted 125 // with a pointer to -1 in the first field. 126 PairWithWeakHandling(WTF::HashTableDeletedValueType) 127 : StrongWeakPair(reinterpret_cast<IntWrapper*>(-1), nullptr) 128 { 129 } 130 131 // Used by the HashTable (via the HashTrait) to skip deleted slots in the 132 // table. Recognizes objects that were 'constructed' using the above 133 // constructor. 134 bool isHashTableDeletedValue() const { return first == reinterpret_cast<IntWrapper*>(-1); } 135 136 // Since we don't allocate independent objects of this type, we don't need 137 // a regular trace method. Instead, we use a traceInCollection method. If 138 // the entry should be deleted from the collection we return true and don't 139 // trace the strong pointer. 140 bool traceInCollection(Visitor* visitor, WTF::ShouldWeakPointersBeMarkedStrongly strongify) 141 { 142 visitor->traceInCollection(second, strongify); 143 if (!visitor->isAlive(second)) 144 return true; 145 visitor->trace(first); 146 return false; 147 } 148 }; 149 150 } 151 152 namespace WTF { 153 154 template<typename T> struct DefaultHash; 155 template<> struct DefaultHash<blink::ThreadMarker> { 156 typedef blink::ThreadMarkerHash Hash; 157 }; 158 159 // ThreadMarkerHash is the default hash for ThreadMarker 160 template<> struct HashTraits<blink::ThreadMarker> : GenericHashTraits<blink::ThreadMarker> { 161 static const bool emptyValueIsZero = true; 162 static void constructDeletedValue(blink::ThreadMarker& slot, bool) { new (NotNull, &slot) blink::ThreadMarker(HashTableDeletedValue); } 163 static bool isDeletedValue(const blink::ThreadMarker& slot) { return slot.isHashTableDeletedValue(); } 164 }; 165 166 // The hash algorithm for our custom pair class is just the standard double 167 // hash for pairs. Note that this means you can't mutate either of the parts of 168 // the pair while they are in the hash table, as that would change their hash 169 // code and thus their preferred placement in the table. 170 template<> struct DefaultHash<blink::PairWithWeakHandling> { 171 typedef PairHash<blink::Member<blink::IntWrapper>, blink::WeakMember<blink::IntWrapper> > Hash; 172 }; 173 174 // Custom traits for the pair. These are weakness handling traits, which means 175 // PairWithWeakHandling must implement the traceInCollection method. 176 // In addition, these traits are concerned with the two magic values for the 177 // object, that represent empty and deleted slots in the hash table. The 178 // SimpleClassHashTraits allow empty slots in the table to be initialzed with 179 // memset to zero, and we use -1 in the first part of the pair to represent 180 // deleted slots. 181 template<> struct HashTraits<blink::PairWithWeakHandling> : blink::WeakHandlingHashTraits<blink::PairWithWeakHandling> { 182 static const bool needsDestruction = false; 183 static const bool hasIsEmptyValueFunction = true; 184 static bool isEmptyValue(const blink::PairWithWeakHandling& value) { return !value.first; } 185 static void constructDeletedValue(blink::PairWithWeakHandling& slot, bool) { new (NotNull, &slot) blink::PairWithWeakHandling(HashTableDeletedValue); } 186 static bool isDeletedValue(const blink::PairWithWeakHandling& value) { return value.isHashTableDeletedValue(); } 187 }; 188 189 } 190 191 namespace blink { 192 193 class TestGCScope { 194 public: 195 explicit TestGCScope(ThreadState::StackState state) 196 : m_state(ThreadState::current()) 197 , m_safePointScope(state) 198 , m_parkedAllThreads(false) 199 { 200 m_state->checkThread(); 201 EXPECT_FALSE(m_state->isInGC()); 202 if (LIKELY(ThreadState::stopThreads())) { 203 m_state->enterGC(); 204 m_parkedAllThreads = true; 205 } 206 } 207 208 bool allThreadsParked() { return m_parkedAllThreads; } 209 210 ~TestGCScope() 211 { 212 // Only cleanup if we parked all threads in which case the GC happened 213 // and we need to resume the other threads. 214 if (LIKELY(m_parkedAllThreads)) { 215 m_state->leaveGC(); 216 EXPECT_FALSE(m_state->isInGC()); 217 ThreadState::resumeThreads(); 218 } 219 } 220 221 private: 222 ThreadState* m_state; 223 ThreadState::SafePointScope m_safePointScope; 224 bool m_parkedAllThreads; // False if we fail to park all threads 225 }; 226 227 static void getHeapStats(HeapStats* stats) 228 { 229 TestGCScope scope(ThreadState::NoHeapPointersOnStack); 230 EXPECT_TRUE(scope.allThreadsParked()); 231 Heap::getStats(stats); 232 } 233 234 #define DEFINE_VISITOR_METHODS(Type) \ 235 virtual void mark(const Type* object, TraceCallback callback) OVERRIDE \ 236 { \ 237 if (object) \ 238 m_count++; \ 239 } \ 240 virtual bool isMarked(const Type*) OVERRIDE { return false; } 241 242 class CountingVisitor : public Visitor { 243 public: 244 CountingVisitor() 245 : m_count(0) 246 { 247 } 248 249 virtual void mark(const void* object, TraceCallback) OVERRIDE 250 { 251 if (object) 252 m_count++; 253 } 254 255 virtual void mark(HeapObjectHeader* header, TraceCallback callback) OVERRIDE 256 { 257 ASSERT(header->payload()); 258 m_count++; 259 } 260 261 virtual void mark(FinalizedHeapObjectHeader* header, TraceCallback callback) OVERRIDE 262 { 263 ASSERT(header->payload()); 264 m_count++; 265 } 266 267 virtual void registerDelayedMarkNoTracing(const void*) OVERRIDE { } 268 virtual void registerWeakMembers(const void*, const void*, WeakPointerCallback) OVERRIDE { } 269 virtual void registerWeakTable(const void*, EphemeronCallback, EphemeronCallback) OVERRIDE { } 270 #if ENABLE(ASSERT) 271 virtual bool weakTableRegistered(const void*) OVERRIDE { return false; } 272 #endif 273 virtual void registerWeakCell(void**, WeakPointerCallback) OVERRIDE { } 274 virtual bool isMarked(const void*) OVERRIDE { return false; } 275 276 FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS) 277 278 size_t count() { return m_count; } 279 void reset() { m_count = 0; } 280 281 private: 282 size_t m_count; 283 }; 284 285 class SimpleObject : public GarbageCollected<SimpleObject> { 286 public: 287 static SimpleObject* create() { return new SimpleObject(); } 288 void trace(Visitor*) { } 289 char getPayload(int i) { return payload[i]; } 290 // This virtual method is unused but it is here to make sure 291 // that this object has a vtable. This object is used 292 // as the super class for objects that also have garbage 293 // collected mixins and having a virtual here makes sure 294 // that adjustment is needed both for marking and for isAlive 295 // checks. 296 virtual void virtualMethod() { } 297 protected: 298 SimpleObject() { } 299 char payload[64]; 300 }; 301 302 #undef DEFINE_VISITOR_METHODS 303 304 class HeapTestSuperClass : public GarbageCollectedFinalized<HeapTestSuperClass> { 305 public: 306 static HeapTestSuperClass* create() 307 { 308 return new HeapTestSuperClass(); 309 } 310 311 virtual ~HeapTestSuperClass() 312 { 313 ++s_destructorCalls; 314 } 315 316 static int s_destructorCalls; 317 void trace(Visitor*) { } 318 319 protected: 320 HeapTestSuperClass() { } 321 }; 322 323 int HeapTestSuperClass::s_destructorCalls = 0; 324 325 class HeapTestOtherSuperClass { 326 public: 327 int payload; 328 }; 329 330 static const size_t classMagic = 0xABCDDBCA; 331 332 class HeapTestSubClass : public HeapTestOtherSuperClass, public HeapTestSuperClass { 333 public: 334 static HeapTestSubClass* create() 335 { 336 return new HeapTestSubClass(); 337 } 338 339 virtual ~HeapTestSubClass() 340 { 341 EXPECT_EQ(classMagic, m_magic); 342 ++s_destructorCalls; 343 } 344 345 static int s_destructorCalls; 346 347 private: 348 349 HeapTestSubClass() : m_magic(classMagic) { } 350 351 const size_t m_magic; 352 }; 353 354 int HeapTestSubClass::s_destructorCalls = 0; 355 356 class HeapAllocatedArray : public GarbageCollected<HeapAllocatedArray> { 357 public: 358 HeapAllocatedArray() 359 { 360 for (int i = 0; i < s_arraySize; ++i) { 361 m_array[i] = i % 128; 362 } 363 } 364 365 int8_t at(size_t i) { return m_array[i]; } 366 void trace(Visitor*) { } 367 private: 368 static const int s_arraySize = 1000; 369 int8_t m_array[s_arraySize]; 370 }; 371 372 // Do several GCs to make sure that later GCs don't free up old memory from 373 // previously run tests in this process. 374 static void clearOutOldGarbage(HeapStats* heapStats) 375 { 376 while (true) { 377 getHeapStats(heapStats); 378 size_t used = heapStats->totalObjectSpace(); 379 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 380 getHeapStats(heapStats); 381 if (heapStats->totalObjectSpace() >= used) 382 break; 383 } 384 } 385 386 class OffHeapInt : public RefCounted<OffHeapInt> { 387 public: 388 static RefPtr<OffHeapInt> create(int x) 389 { 390 return adoptRef(new OffHeapInt(x)); 391 } 392 393 virtual ~OffHeapInt() 394 { 395 ++s_destructorCalls; 396 } 397 398 static int s_destructorCalls; 399 400 int value() const { return m_x; } 401 402 bool operator==(const OffHeapInt& other) const { return other.value() == value(); } 403 404 unsigned hash() { return IntHash<int>::hash(m_x); } 405 void voidFunction() { } 406 407 protected: 408 OffHeapInt(int x) : m_x(x) { } 409 410 private: 411 OffHeapInt(); 412 int m_x; 413 }; 414 415 int IntWrapper::s_destructorCalls = 0; 416 int OffHeapInt::s_destructorCalls = 0; 417 418 class ThreadedTesterBase { 419 protected: 420 static void test(ThreadedTesterBase* tester) 421 { 422 Vector<OwnPtr<WebThread>, numberOfThreads> m_threads; 423 for (int i = 0; i < numberOfThreads; i++) { 424 m_threads.append(adoptPtr(Platform::current()->createThread("blink gc testing thread"))); 425 m_threads.last()->postTask(new Task(WTF::bind(threadFunc, tester))); 426 } 427 while (tester->m_threadsToFinish) { 428 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack); 429 Platform::current()->yieldCurrentThread(); 430 } 431 delete tester; 432 } 433 434 virtual void runThread() = 0; 435 436 protected: 437 static const int numberOfThreads = 10; 438 static const int gcPerThread = 5; 439 static const int numberOfAllocations = 50; 440 441 ThreadedTesterBase() : m_gcCount(0), m_threadsToFinish(numberOfThreads) 442 { 443 } 444 445 virtual ~ThreadedTesterBase() 446 { 447 } 448 449 inline bool done() const { return m_gcCount >= numberOfThreads * gcPerThread; } 450 451 volatile int m_gcCount; 452 volatile int m_threadsToFinish; 453 454 private: 455 static void threadFunc(void* data) 456 { 457 reinterpret_cast<ThreadedTesterBase*>(data)->runThread(); 458 } 459 }; 460 461 class ThreadedHeapTester : public ThreadedTesterBase { 462 public: 463 static void test() 464 { 465 ThreadedTesterBase::test(new ThreadedHeapTester); 466 } 467 468 protected: 469 virtual void runThread() OVERRIDE 470 { 471 ThreadState::attach(); 472 473 int gcCount = 0; 474 while (!done()) { 475 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack); 476 { 477 Persistent<IntWrapper> wrapper; 478 479 typedef Persistent<IntWrapper, GlobalPersistents> GlobalIntWrapperPersistent; 480 OwnPtr<GlobalIntWrapperPersistent> globalPersistent = adoptPtr(new GlobalIntWrapperPersistent(IntWrapper::create(0x0ed0cabb))); 481 482 for (int i = 0; i < numberOfAllocations; i++) { 483 wrapper = IntWrapper::create(0x0bbac0de); 484 if (!(i % 10)) { 485 globalPersistent = adoptPtr(new GlobalIntWrapperPersistent(IntWrapper::create(0x0ed0cabb))); 486 } 487 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack); 488 Platform::current()->yieldCurrentThread(); 489 } 490 491 if (gcCount < gcPerThread) { 492 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 493 gcCount++; 494 atomicIncrement(&m_gcCount); 495 } 496 497 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 498 EXPECT_EQ(wrapper->value(), 0x0bbac0de); 499 EXPECT_EQ((*globalPersistent)->value(), 0x0ed0cabb); 500 } 501 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack); 502 Platform::current()->yieldCurrentThread(); 503 } 504 ThreadState::detach(); 505 atomicDecrement(&m_threadsToFinish); 506 } 507 }; 508 509 class ThreadedWeaknessTester : public ThreadedTesterBase { 510 public: 511 static void test() 512 { 513 ThreadedTesterBase::test(new ThreadedWeaknessTester); 514 } 515 516 private: 517 virtual void runThread() OVERRIDE 518 { 519 ThreadState::attach(); 520 521 int gcCount = 0; 522 while (!done()) { 523 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack); 524 { 525 Persistent<HeapHashMap<ThreadMarker, WeakMember<IntWrapper> > > weakMap = new HeapHashMap<ThreadMarker, WeakMember<IntWrapper> >; 526 PersistentHeapHashMap<ThreadMarker, WeakMember<IntWrapper> > weakMap2; 527 528 for (int i = 0; i < numberOfAllocations; i++) { 529 weakMap->add(static_cast<unsigned>(i), IntWrapper::create(0)); 530 weakMap2.add(static_cast<unsigned>(i), IntWrapper::create(0)); 531 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack); 532 Platform::current()->yieldCurrentThread(); 533 } 534 535 if (gcCount < gcPerThread) { 536 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 537 gcCount++; 538 atomicIncrement(&m_gcCount); 539 } 540 541 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 542 EXPECT_TRUE(weakMap->isEmpty()); 543 EXPECT_TRUE(weakMap2.isEmpty()); 544 } 545 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack); 546 Platform::current()->yieldCurrentThread(); 547 } 548 ThreadState::detach(); 549 atomicDecrement(&m_threadsToFinish); 550 } 551 }; 552 553 // The accounting for memory includes the memory used by rounding up object 554 // sizes. This is done in a different way on 32 bit and 64 bit, so we have to 555 // have some slack in the tests. 556 template<typename T> 557 void CheckWithSlack(T expected, T actual, int slack) 558 { 559 EXPECT_LE(expected, actual); 560 EXPECT_GE((intptr_t)expected + slack, (intptr_t)actual); 561 } 562 563 class TraceCounter : public GarbageCollectedFinalized<TraceCounter> { 564 public: 565 static TraceCounter* create() 566 { 567 return new TraceCounter(); 568 } 569 570 void trace(Visitor*) { m_traceCount++; } 571 572 int traceCount() { return m_traceCount; } 573 574 private: 575 TraceCounter() 576 : m_traceCount(0) 577 { 578 } 579 580 int m_traceCount; 581 }; 582 583 class ClassWithMember : public GarbageCollected<ClassWithMember> { 584 public: 585 static ClassWithMember* create() 586 { 587 return new ClassWithMember(); 588 } 589 590 void trace(Visitor* visitor) 591 { 592 EXPECT_TRUE(visitor->isMarked(this)); 593 if (!traceCount()) 594 EXPECT_FALSE(visitor->isMarked(m_traceCounter)); 595 else 596 EXPECT_TRUE(visitor->isMarked(m_traceCounter)); 597 598 visitor->trace(m_traceCounter); 599 } 600 601 int traceCount() { return m_traceCounter->traceCount(); } 602 603 private: 604 ClassWithMember() 605 : m_traceCounter(TraceCounter::create()) 606 { } 607 608 Member<TraceCounter> m_traceCounter; 609 }; 610 611 class SimpleFinalizedObject : public GarbageCollectedFinalized<SimpleFinalizedObject> { 612 public: 613 static SimpleFinalizedObject* create() 614 { 615 return new SimpleFinalizedObject(); 616 } 617 618 ~SimpleFinalizedObject() 619 { 620 ++s_destructorCalls; 621 } 622 623 static int s_destructorCalls; 624 625 void trace(Visitor*) { } 626 627 private: 628 SimpleFinalizedObject() { } 629 }; 630 631 int SimpleFinalizedObject::s_destructorCalls = 0; 632 633 class Node : public GarbageCollected<Node> { 634 public: 635 static Node* create(int i) 636 { 637 return new Node(i); 638 } 639 640 void trace(Visitor*) { } 641 642 int value() { return m_value; } 643 644 private: 645 Node(int i) : m_value(i) { } 646 int m_value; 647 }; 648 649 class Bar : public GarbageCollectedFinalized<Bar> { 650 public: 651 static Bar* create() 652 { 653 return new Bar(); 654 } 655 656 void finalizeGarbageCollectedObject() 657 { 658 EXPECT_TRUE(m_magic == magic); 659 m_magic = 0; 660 s_live--; 661 } 662 bool hasBeenFinalized() const { return !m_magic; } 663 664 virtual void trace(Visitor* visitor) { } 665 static unsigned s_live; 666 667 protected: 668 static const int magic = 1337; 669 int m_magic; 670 671 Bar() 672 : m_magic(magic) 673 { 674 s_live++; 675 } 676 }; 677 678 unsigned Bar::s_live = 0; 679 680 class Baz : public GarbageCollected<Baz> { 681 public: 682 static Baz* create(Bar* bar) 683 { 684 return new Baz(bar); 685 } 686 687 void trace(Visitor* visitor) 688 { 689 visitor->trace(m_bar); 690 } 691 692 void clear() { m_bar.release(); } 693 694 // willFinalize is called by FinalizationObserver. 695 void willFinalize() 696 { 697 EXPECT_TRUE(!m_bar->hasBeenFinalized()); 698 } 699 700 private: 701 explicit Baz(Bar* bar) 702 : m_bar(bar) 703 { 704 } 705 706 Member<Bar> m_bar; 707 }; 708 709 class Foo : public Bar { 710 public: 711 static Foo* create(Bar* bar) 712 { 713 return new Foo(bar); 714 } 715 716 static Foo* create(Foo* foo) 717 { 718 return new Foo(foo); 719 } 720 721 virtual void trace(Visitor* visitor) OVERRIDE 722 { 723 if (m_pointsToFoo) 724 visitor->mark(static_cast<Foo*>(m_bar)); 725 else 726 visitor->mark(m_bar); 727 } 728 729 private: 730 Foo(Bar* bar) 731 : Bar() 732 , m_bar(bar) 733 , m_pointsToFoo(false) 734 { 735 } 736 737 Foo(Foo* foo) 738 : Bar() 739 , m_bar(foo) 740 , m_pointsToFoo(true) 741 { 742 } 743 744 Bar* m_bar; 745 bool m_pointsToFoo; 746 }; 747 748 class Bars : public Bar { 749 public: 750 static Bars* create() 751 { 752 return new Bars(); 753 } 754 755 virtual void trace(Visitor* visitor) OVERRIDE 756 { 757 for (unsigned i = 0; i < m_width; i++) 758 visitor->trace(m_bars[i]); 759 } 760 761 unsigned getWidth() const 762 { 763 return m_width; 764 } 765 766 static const unsigned width = 7500; 767 private: 768 Bars() : m_width(0) 769 { 770 for (unsigned i = 0; i < width; i++) { 771 m_bars[i] = Bar::create(); 772 m_width++; 773 } 774 } 775 776 unsigned m_width; 777 Member<Bar> m_bars[width]; 778 }; 779 780 class ConstructorAllocation : public GarbageCollected<ConstructorAllocation> { 781 public: 782 static ConstructorAllocation* create() { return new ConstructorAllocation(); } 783 784 void trace(Visitor* visitor) { visitor->trace(m_intWrapper); } 785 786 private: 787 ConstructorAllocation() 788 { 789 m_intWrapper = IntWrapper::create(42); 790 } 791 792 Member<IntWrapper> m_intWrapper; 793 }; 794 795 class LargeObject : public GarbageCollectedFinalized<LargeObject> { 796 public: 797 ~LargeObject() 798 { 799 s_destructorCalls++; 800 } 801 static LargeObject* create() { return new LargeObject(); } 802 char get(size_t i) { return m_data[i]; } 803 void set(size_t i, char c) { m_data[i] = c; } 804 size_t length() { return s_length; } 805 void trace(Visitor* visitor) 806 { 807 visitor->trace(m_intWrapper); 808 } 809 static int s_destructorCalls; 810 811 private: 812 static const size_t s_length = 1024*1024; 813 LargeObject() 814 { 815 m_intWrapper = IntWrapper::create(23); 816 } 817 Member<IntWrapper> m_intWrapper; 818 char m_data[s_length]; 819 }; 820 821 int LargeObject::s_destructorCalls = 0; 822 823 class RefCountedAndGarbageCollected : public RefCountedGarbageCollected<RefCountedAndGarbageCollected> { 824 public: 825 static PassRefPtr<RefCountedAndGarbageCollected> create() 826 { 827 return adoptRef(new RefCountedAndGarbageCollected()); 828 } 829 830 ~RefCountedAndGarbageCollected() 831 { 832 ++s_destructorCalls; 833 } 834 835 // These are here with their default implementations so you can break in 836 // them in the debugger. 837 void ref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::ref(); } 838 void deref() { RefCountedGarbageCollected<RefCountedAndGarbageCollected>::deref(); } 839 840 void trace(Visitor*) { } 841 842 static int s_destructorCalls; 843 844 private: 845 RefCountedAndGarbageCollected() 846 { 847 } 848 }; 849 850 int RefCountedAndGarbageCollected::s_destructorCalls = 0; 851 852 class RefCountedAndGarbageCollected2 : public HeapTestOtherSuperClass, public RefCountedGarbageCollected<RefCountedAndGarbageCollected2> { 853 public: 854 static RefCountedAndGarbageCollected2* create() 855 { 856 return adoptRefCountedGarbageCollected(new RefCountedAndGarbageCollected2()); 857 } 858 859 ~RefCountedAndGarbageCollected2() 860 { 861 ++s_destructorCalls; 862 } 863 864 void trace(Visitor*) { } 865 866 static int s_destructorCalls; 867 868 private: 869 RefCountedAndGarbageCollected2() 870 { 871 } 872 }; 873 874 int RefCountedAndGarbageCollected2::s_destructorCalls = 0; 875 876 #define DEFINE_VISITOR_METHODS(Type) \ 877 virtual void mark(const Type* object, TraceCallback callback) OVERRIDE \ 878 { \ 879 mark(object); \ 880 } \ 881 882 class RefCountedGarbageCollectedVisitor : public CountingVisitor { 883 public: 884 RefCountedGarbageCollectedVisitor(int expected, void** objects) 885 : m_count(0) 886 , m_expectedCount(expected) 887 , m_expectedObjects(objects) 888 { 889 } 890 891 void mark(const void* ptr) { markNoTrace(ptr); } 892 893 virtual void markNoTrace(const void* ptr) 894 { 895 if (!ptr) 896 return; 897 if (m_count < m_expectedCount) 898 EXPECT_TRUE(expectedObject(ptr)); 899 else 900 EXPECT_FALSE(expectedObject(ptr)); 901 m_count++; 902 } 903 904 virtual void mark(const void* ptr, TraceCallback) OVERRIDE 905 { 906 mark(ptr); 907 } 908 909 virtual void mark(HeapObjectHeader* header, TraceCallback callback) OVERRIDE 910 { 911 mark(header->payload()); 912 } 913 914 virtual void mark(FinalizedHeapObjectHeader* header, TraceCallback callback) OVERRIDE 915 { 916 mark(header->payload()); 917 } 918 919 bool validate() { return m_count >= m_expectedCount; } 920 void reset() { m_count = 0; } 921 922 FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS) 923 924 private: 925 bool expectedObject(const void* ptr) 926 { 927 for (int i = 0; i < m_expectedCount; i++) { 928 if (m_expectedObjects[i] == ptr) 929 return true; 930 } 931 return false; 932 } 933 934 int m_count; 935 int m_expectedCount; 936 void** m_expectedObjects; 937 }; 938 939 #undef DEFINE_VISITOR_METHODS 940 941 class Weak : public Bar { 942 public: 943 static Weak* create(Bar* strong, Bar* weak) 944 { 945 return new Weak(strong, weak); 946 } 947 948 virtual void trace(Visitor* visitor) OVERRIDE 949 { 950 visitor->trace(m_strongBar); 951 visitor->registerWeakMembers(this, zapWeakMembers); 952 } 953 954 static void zapWeakMembers(Visitor* visitor, void* self) 955 { 956 reinterpret_cast<Weak*>(self)->zapWeakMembers(visitor); 957 } 958 959 bool strongIsThere() { return !!m_strongBar; } 960 bool weakIsThere() { return !!m_weakBar; } 961 962 private: 963 Weak(Bar* strongBar, Bar* weakBar) 964 : Bar() 965 , m_strongBar(strongBar) 966 , m_weakBar(weakBar) 967 { 968 } 969 970 void zapWeakMembers(Visitor* visitor) 971 { 972 if (!visitor->isAlive(m_weakBar)) 973 m_weakBar = 0; 974 } 975 976 Member<Bar> m_strongBar; 977 Bar* m_weakBar; 978 }; 979 980 class WithWeakMember : public Bar { 981 public: 982 static WithWeakMember* create(Bar* strong, Bar* weak) 983 { 984 return new WithWeakMember(strong, weak); 985 } 986 987 virtual void trace(Visitor* visitor) OVERRIDE 988 { 989 visitor->trace(m_strongBar); 990 visitor->trace(m_weakBar); 991 } 992 993 bool strongIsThere() { return !!m_strongBar; } 994 bool weakIsThere() { return !!m_weakBar; } 995 996 private: 997 WithWeakMember(Bar* strongBar, Bar* weakBar) 998 : Bar() 999 , m_strongBar(strongBar) 1000 , m_weakBar(weakBar) 1001 { 1002 } 1003 1004 Member<Bar> m_strongBar; 1005 WeakMember<Bar> m_weakBar; 1006 }; 1007 1008 class Observable : public GarbageCollectedFinalized<Observable> { 1009 public: 1010 static Observable* create(Bar* bar) { return new Observable(bar); } 1011 ~Observable() { m_wasDestructed = true; } 1012 void trace(Visitor* visitor) { visitor->trace(m_bar); } 1013 1014 // willFinalize is called by FinalizationObserver. willFinalize can touch 1015 // other on-heap objects. 1016 void willFinalize() 1017 { 1018 EXPECT_FALSE(m_wasDestructed); 1019 EXPECT_FALSE(m_bar->hasBeenFinalized()); 1020 } 1021 1022 private: 1023 explicit Observable(Bar* bar) 1024 : m_bar(bar) 1025 , m_wasDestructed(false) 1026 { 1027 } 1028 1029 Member<Bar> m_bar; 1030 bool m_wasDestructed; 1031 }; 1032 1033 template <typename T> class FinalizationObserver : public GarbageCollected<FinalizationObserver<T> > { 1034 public: 1035 static FinalizationObserver* create(T* data) { return new FinalizationObserver(data); } 1036 bool didCallWillFinalize() const { return m_didCallWillFinalize; } 1037 1038 void trace(Visitor* visitor) 1039 { 1040 visitor->registerWeakMembers(this, zapWeakMembers); 1041 } 1042 1043 private: 1044 FinalizationObserver(T* data) 1045 : m_data(data) 1046 , m_didCallWillFinalize(false) 1047 { 1048 } 1049 1050 static void zapWeakMembers(Visitor* visitor, void* self) 1051 { 1052 FinalizationObserver* o = reinterpret_cast<FinalizationObserver*>(self); 1053 if (o->m_data && !visitor->isAlive(o->m_data)) { 1054 o->m_data->willFinalize(); 1055 o->m_data = nullptr; 1056 o->m_didCallWillFinalize = true; 1057 } 1058 } 1059 1060 WeakMember<T> m_data; 1061 bool m_didCallWillFinalize; 1062 }; 1063 1064 class FinalizationObserverWithHashMap { 1065 public: 1066 typedef HeapHashMap<WeakMember<Observable>, OwnPtr<FinalizationObserverWithHashMap> > ObserverMap; 1067 1068 explicit FinalizationObserverWithHashMap(Observable& target) : m_target(target) { } 1069 ~FinalizationObserverWithHashMap() 1070 { 1071 m_target.willFinalize(); 1072 s_didCallWillFinalize = true; 1073 } 1074 1075 static ObserverMap& observe(Observable& target) 1076 { 1077 ObserverMap& map = observers(); 1078 ObserverMap::AddResult result = map.add(&target, nullptr); 1079 if (result.isNewEntry) 1080 result.storedValue->value = adoptPtr(new FinalizationObserverWithHashMap(target)); 1081 else 1082 ASSERT(result.storedValue->value); 1083 return map; 1084 } 1085 1086 static bool s_didCallWillFinalize; 1087 1088 private: 1089 static ObserverMap& observers() 1090 { 1091 DEFINE_STATIC_LOCAL(Persistent<ObserverMap>, observerMap, ()); 1092 if (!observerMap) 1093 observerMap = new ObserverMap(); 1094 return *observerMap; 1095 } 1096 1097 Observable& m_target; 1098 }; 1099 1100 bool FinalizationObserverWithHashMap::s_didCallWillFinalize = false; 1101 1102 class SuperClass; 1103 1104 class PointsBack : public RefCountedWillBeGarbageCollectedFinalized<PointsBack> { 1105 public: 1106 static PassRefPtrWillBeRawPtr<PointsBack> create() 1107 { 1108 return adoptRefWillBeNoop(new PointsBack()); 1109 } 1110 1111 ~PointsBack() 1112 { 1113 --s_aliveCount; 1114 } 1115 1116 void setBackPointer(SuperClass* backPointer) 1117 { 1118 m_backPointer = backPointer; 1119 } 1120 1121 SuperClass* backPointer() const { return m_backPointer; } 1122 1123 void trace(Visitor* visitor) 1124 { 1125 #if ENABLE_OILPAN 1126 visitor->trace(m_backPointer); 1127 #endif 1128 } 1129 1130 static int s_aliveCount; 1131 private: 1132 PointsBack() : m_backPointer(nullptr) 1133 { 1134 ++s_aliveCount; 1135 } 1136 1137 RawPtrWillBeWeakMember<SuperClass> m_backPointer; 1138 }; 1139 1140 int PointsBack::s_aliveCount = 0; 1141 1142 class SuperClass : public RefCountedWillBeGarbageCollectedFinalized<SuperClass> { 1143 public: 1144 static PassRefPtrWillBeRawPtr<SuperClass> create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack) 1145 { 1146 return adoptRefWillBeNoop(new SuperClass(pointsBack)); 1147 } 1148 1149 virtual ~SuperClass() 1150 { 1151 #if !ENABLE_OILPAN 1152 m_pointsBack->setBackPointer(0); 1153 #endif 1154 --s_aliveCount; 1155 } 1156 1157 void doStuff(PassRefPtrWillBeRawPtr<SuperClass> targetPass, PointsBack* pointsBack, int superClassCount) 1158 { 1159 RefPtrWillBeRawPtr<SuperClass> target = targetPass; 1160 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 1161 EXPECT_EQ(pointsBack, target->pointsBack()); 1162 EXPECT_EQ(superClassCount, SuperClass::s_aliveCount); 1163 } 1164 1165 virtual void trace(Visitor* visitor) 1166 { 1167 #if ENABLE_OILPAN 1168 visitor->trace(m_pointsBack); 1169 #endif 1170 } 1171 1172 PointsBack* pointsBack() const { return m_pointsBack.get(); } 1173 1174 static int s_aliveCount; 1175 protected: 1176 explicit SuperClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack) 1177 : m_pointsBack(pointsBack) 1178 { 1179 m_pointsBack->setBackPointer(this); 1180 ++s_aliveCount; 1181 } 1182 1183 private: 1184 RefPtrWillBeMember<PointsBack> m_pointsBack; 1185 }; 1186 1187 int SuperClass::s_aliveCount = 0; 1188 class SubData : public NoBaseWillBeGarbageCollectedFinalized<SubData> { 1189 public: 1190 SubData() { ++s_aliveCount; } 1191 ~SubData() { --s_aliveCount; } 1192 1193 void trace(Visitor*) { } 1194 1195 static int s_aliveCount; 1196 }; 1197 1198 int SubData::s_aliveCount = 0; 1199 1200 class SubClass : public SuperClass { 1201 public: 1202 static PassRefPtrWillBeRawPtr<SubClass> create(PassRefPtrWillBeRawPtr<PointsBack> pointsBack) 1203 { 1204 return adoptRefWillBeNoop(new SubClass(pointsBack)); 1205 } 1206 1207 virtual ~SubClass() 1208 { 1209 --s_aliveCount; 1210 } 1211 1212 virtual void trace(Visitor* visitor) 1213 { 1214 #if ENABLE_OILPAN 1215 SuperClass::trace(visitor); 1216 visitor->trace(m_data); 1217 #endif 1218 } 1219 1220 static int s_aliveCount; 1221 private: 1222 explicit SubClass(PassRefPtrWillBeRawPtr<PointsBack> pointsBack) 1223 : SuperClass(pointsBack) 1224 , m_data(adoptPtrWillBeNoop(new SubData())) 1225 { 1226 ++s_aliveCount; 1227 } 1228 1229 private: 1230 OwnPtrWillBeMember<SubData> m_data; 1231 }; 1232 1233 int SubClass::s_aliveCount = 0; 1234 1235 class TransitionRefCounted : public RefCountedWillBeRefCountedGarbageCollected<TransitionRefCounted> { 1236 public: 1237 static PassRefPtrWillBeRawPtr<TransitionRefCounted> create() 1238 { 1239 return adoptRefWillBeRefCountedGarbageCollected(new TransitionRefCounted()); 1240 } 1241 1242 ~TransitionRefCounted() 1243 { 1244 --s_aliveCount; 1245 } 1246 1247 void trace(Visitor* visitor) { } 1248 1249 static int s_aliveCount; 1250 1251 private: 1252 TransitionRefCounted() 1253 { 1254 ++s_aliveCount; 1255 } 1256 }; 1257 1258 int TransitionRefCounted::s_aliveCount = 0; 1259 1260 class Mixin : public GarbageCollectedMixin { 1261 public: 1262 virtual void trace(Visitor* visitor) { } 1263 1264 virtual char getPayload(int i) { return m_padding[i]; } 1265 1266 protected: 1267 int m_padding[8]; 1268 }; 1269 1270 class UseMixin : public SimpleObject, public Mixin { 1271 USING_GARBAGE_COLLECTED_MIXIN(UseMixin) 1272 public: 1273 static UseMixin* create() 1274 { 1275 return new UseMixin(); 1276 } 1277 1278 static int s_traceCount; 1279 virtual void trace(Visitor* visitor) 1280 { 1281 SimpleObject::trace(visitor); 1282 Mixin::trace(visitor); 1283 ++s_traceCount; 1284 } 1285 1286 private: 1287 UseMixin() 1288 { 1289 s_traceCount = 0; 1290 } 1291 }; 1292 1293 int UseMixin::s_traceCount = 0; 1294 1295 class VectorObject { 1296 ALLOW_ONLY_INLINE_ALLOCATION(); 1297 public: 1298 VectorObject() 1299 { 1300 m_value = SimpleFinalizedObject::create(); 1301 } 1302 1303 void trace(Visitor* visitor) 1304 { 1305 visitor->trace(m_value); 1306 } 1307 1308 private: 1309 Member<SimpleFinalizedObject> m_value; 1310 }; 1311 1312 class VectorObjectInheritedTrace : public VectorObject { }; 1313 1314 class VectorObjectNoTrace { 1315 ALLOW_ONLY_INLINE_ALLOCATION(); 1316 public: 1317 VectorObjectNoTrace() 1318 { 1319 m_value = SimpleFinalizedObject::create(); 1320 } 1321 1322 private: 1323 Member<SimpleFinalizedObject> m_value; 1324 }; 1325 1326 class TerminatedArrayItem { 1327 ALLOW_ONLY_INLINE_ALLOCATION(); 1328 public: 1329 TerminatedArrayItem(IntWrapper* payload) : m_payload(payload), m_isLast(false) { } 1330 1331 void trace(Visitor* visitor) { visitor->trace(m_payload); } 1332 1333 bool isLastInArray() const { return m_isLast; } 1334 void setLastInArray(bool value) { m_isLast = value; } 1335 1336 IntWrapper* payload() const { return m_payload; } 1337 1338 private: 1339 Member<IntWrapper> m_payload; 1340 bool m_isLast; 1341 }; 1342 1343 } // namespace blink 1344 1345 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::VectorObject); 1346 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::VectorObjectInheritedTrace); 1347 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::VectorObjectNoTrace); 1348 1349 namespace blink { 1350 1351 class OneKiloByteObject : public GarbageCollectedFinalized<OneKiloByteObject> { 1352 public: 1353 ~OneKiloByteObject() { s_destructorCalls++; } 1354 char* data() { return m_data; } 1355 void trace(Visitor* visitor) { } 1356 static int s_destructorCalls; 1357 1358 private: 1359 static const size_t s_length = 1024; 1360 char m_data[s_length]; 1361 }; 1362 1363 int OneKiloByteObject::s_destructorCalls = 0; 1364 1365 class DynamicallySizedObject : public GarbageCollected<DynamicallySizedObject> { 1366 public: 1367 static DynamicallySizedObject* create(size_t size) 1368 { 1369 void* slot = Heap::allocate<DynamicallySizedObject>(size); 1370 return new (slot) DynamicallySizedObject(); 1371 } 1372 1373 void* operator new(std::size_t, void* location) 1374 { 1375 return location; 1376 } 1377 1378 uint8_t get(int i) 1379 { 1380 return *(reinterpret_cast<uint8_t*>(this) + i); 1381 } 1382 1383 void trace(Visitor*) { } 1384 1385 private: 1386 DynamicallySizedObject() { } 1387 }; 1388 1389 class FinalizationAllocator : public GarbageCollectedFinalized<FinalizationAllocator> { 1390 public: 1391 FinalizationAllocator(Persistent<IntWrapper>* wrapper) 1392 : m_wrapper(wrapper) 1393 { 1394 } 1395 1396 ~FinalizationAllocator() 1397 { 1398 for (int i = 0; i < 10; ++i) 1399 *m_wrapper = IntWrapper::create(42); 1400 for (int i = 0; i < 512; ++i) 1401 new OneKiloByteObject(); 1402 } 1403 1404 void trace(Visitor*) { } 1405 1406 private: 1407 Persistent<IntWrapper>* m_wrapper; 1408 }; 1409 1410 TEST(HeapTest, Transition) 1411 { 1412 { 1413 RefPtr<TransitionRefCounted> refCounted = TransitionRefCounted::create(); 1414 EXPECT_EQ(1, TransitionRefCounted::s_aliveCount); 1415 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1416 EXPECT_EQ(1, TransitionRefCounted::s_aliveCount); 1417 } 1418 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1419 EXPECT_EQ(0, TransitionRefCounted::s_aliveCount); 1420 1421 RefPtrWillBePersistent<PointsBack> pointsBack1 = PointsBack::create(); 1422 RefPtrWillBePersistent<PointsBack> pointsBack2 = PointsBack::create(); 1423 RefPtrWillBePersistent<SuperClass> superClass = SuperClass::create(pointsBack1); 1424 RefPtrWillBePersistent<SubClass> subClass = SubClass::create(pointsBack2); 1425 EXPECT_EQ(2, PointsBack::s_aliveCount); 1426 EXPECT_EQ(2, SuperClass::s_aliveCount); 1427 EXPECT_EQ(1, SubClass::s_aliveCount); 1428 EXPECT_EQ(1, SubData::s_aliveCount); 1429 1430 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1431 EXPECT_EQ(0, TransitionRefCounted::s_aliveCount); 1432 EXPECT_EQ(2, PointsBack::s_aliveCount); 1433 EXPECT_EQ(2, SuperClass::s_aliveCount); 1434 EXPECT_EQ(1, SubClass::s_aliveCount); 1435 EXPECT_EQ(1, SubData::s_aliveCount); 1436 1437 superClass->doStuff(superClass.release(), pointsBack1.get(), 2); 1438 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1439 EXPECT_EQ(2, PointsBack::s_aliveCount); 1440 EXPECT_EQ(1, SuperClass::s_aliveCount); 1441 EXPECT_EQ(1, SubClass::s_aliveCount); 1442 EXPECT_EQ(1, SubData::s_aliveCount); 1443 EXPECT_EQ(0, pointsBack1->backPointer()); 1444 1445 pointsBack1.release(); 1446 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1447 EXPECT_EQ(1, PointsBack::s_aliveCount); 1448 EXPECT_EQ(1, SuperClass::s_aliveCount); 1449 EXPECT_EQ(1, SubClass::s_aliveCount); 1450 EXPECT_EQ(1, SubData::s_aliveCount); 1451 1452 subClass->doStuff(subClass.release(), pointsBack2.get(), 1); 1453 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1454 EXPECT_EQ(1, PointsBack::s_aliveCount); 1455 EXPECT_EQ(0, SuperClass::s_aliveCount); 1456 EXPECT_EQ(0, SubClass::s_aliveCount); 1457 EXPECT_EQ(0, SubData::s_aliveCount); 1458 EXPECT_EQ(0, pointsBack2->backPointer()); 1459 1460 pointsBack2.release(); 1461 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1462 EXPECT_EQ(0, PointsBack::s_aliveCount); 1463 EXPECT_EQ(0, SuperClass::s_aliveCount); 1464 EXPECT_EQ(0, SubClass::s_aliveCount); 1465 EXPECT_EQ(0, SubData::s_aliveCount); 1466 1467 EXPECT_TRUE(superClass == subClass); 1468 } 1469 1470 TEST(HeapTest, Threading) 1471 { 1472 ThreadedHeapTester::test(); 1473 } 1474 1475 TEST(HeapTest, ThreadedWeakness) 1476 { 1477 ThreadedWeaknessTester::test(); 1478 } 1479 1480 TEST(HeapTest, BasicFunctionality) 1481 { 1482 HeapStats heapStats; 1483 clearOutOldGarbage(&heapStats); 1484 { 1485 size_t slack = 0; 1486 1487 // When the test starts there may already have been leaked some memory 1488 // on the heap, so we establish a base line. 1489 size_t baseLevel = heapStats.totalObjectSpace(); 1490 bool testPagesAllocated = !baseLevel; 1491 if (testPagesAllocated) 1492 EXPECT_EQ(heapStats.totalAllocatedSpace(), 0ul); 1493 1494 // This allocates objects on the general heap which should add a page of memory. 1495 DynamicallySizedObject* alloc32 = DynamicallySizedObject::create(32); 1496 slack += 4; 1497 memset(alloc32, 40, 32); 1498 DynamicallySizedObject* alloc64 = DynamicallySizedObject::create(64); 1499 slack += 4; 1500 memset(alloc64, 27, 64); 1501 1502 size_t total = 96; 1503 1504 getHeapStats(&heapStats); 1505 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack); 1506 if (testPagesAllocated) 1507 EXPECT_EQ(heapStats.totalAllocatedSpace(), blinkPageSize); 1508 1509 CheckWithSlack(alloc32 + 32 + sizeof(FinalizedHeapObjectHeader), alloc64, slack); 1510 1511 EXPECT_EQ(alloc32->get(0), 40); 1512 EXPECT_EQ(alloc32->get(31), 40); 1513 EXPECT_EQ(alloc64->get(0), 27); 1514 EXPECT_EQ(alloc64->get(63), 27); 1515 1516 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 1517 1518 EXPECT_EQ(alloc32->get(0), 40); 1519 EXPECT_EQ(alloc32->get(31), 40); 1520 EXPECT_EQ(alloc64->get(0), 27); 1521 EXPECT_EQ(alloc64->get(63), 27); 1522 } 1523 1524 clearOutOldGarbage(&heapStats); 1525 size_t total = 0; 1526 size_t slack = 0; 1527 size_t baseLevel = heapStats.totalObjectSpace(); 1528 bool testPagesAllocated = !baseLevel; 1529 if (testPagesAllocated) 1530 EXPECT_EQ(heapStats.totalAllocatedSpace(), 0ul); 1531 1532 size_t big = 1008; 1533 Persistent<DynamicallySizedObject> bigArea = DynamicallySizedObject::create(big); 1534 total += big; 1535 slack += 4; 1536 1537 size_t persistentCount = 0; 1538 const size_t numPersistents = 100000; 1539 Persistent<DynamicallySizedObject>* persistents[numPersistents]; 1540 1541 for (int i = 0; i < 1000; i++) { 1542 size_t size = 128 + i * 8; 1543 total += size; 1544 persistents[persistentCount++] = new Persistent<DynamicallySizedObject>(DynamicallySizedObject::create(size)); 1545 slack += 4; 1546 getHeapStats(&heapStats); 1547 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack); 1548 if (testPagesAllocated) 1549 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1)); 1550 } 1551 1552 { 1553 DynamicallySizedObject* alloc32b(DynamicallySizedObject::create(32)); 1554 slack += 4; 1555 memset(alloc32b, 40, 32); 1556 DynamicallySizedObject* alloc64b(DynamicallySizedObject::create(64)); 1557 slack += 4; 1558 memset(alloc64b, 27, 64); 1559 EXPECT_TRUE(alloc32b != alloc64b); 1560 1561 total += 96; 1562 getHeapStats(&heapStats); 1563 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack); 1564 if (testPagesAllocated) 1565 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1)); 1566 } 1567 1568 clearOutOldGarbage(&heapStats); 1569 total -= 96; 1570 slack -= 8; 1571 if (testPagesAllocated) 1572 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1)); 1573 1574 DynamicallySizedObject* bigAreaRaw = bigArea; 1575 // Clear the persistent, so that the big area will be garbage collected. 1576 bigArea.release(); 1577 clearOutOldGarbage(&heapStats); 1578 1579 total -= big; 1580 slack -= 4; 1581 getHeapStats(&heapStats); 1582 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack); 1583 if (testPagesAllocated) 1584 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1)); 1585 1586 // Endless loop unless we eventually get the memory back that we just freed. 1587 while (true) { 1588 Persistent<DynamicallySizedObject>* alloc = new Persistent<DynamicallySizedObject>(DynamicallySizedObject::create(big / 2)); 1589 slack += 4; 1590 persistents[persistentCount++] = alloc; 1591 EXPECT_LT(persistentCount, numPersistents); 1592 total += big / 2; 1593 if (bigAreaRaw == alloc->get()) 1594 break; 1595 } 1596 1597 getHeapStats(&heapStats); 1598 CheckWithSlack(baseLevel + total, heapStats.totalObjectSpace(), slack); 1599 if (testPagesAllocated) 1600 EXPECT_EQ(0ul, heapStats.totalAllocatedSpace() & (blinkPageSize - 1)); 1601 1602 for (size_t i = 0; i < persistentCount; i++) { 1603 delete persistents[i]; 1604 persistents[i] = 0; 1605 } 1606 1607 uint8_t* address = reinterpret_cast<uint8_t*>(Heap::reallocate<DynamicallySizedObject>(0, 100)); 1608 for (int i = 0; i < 100; i++) 1609 address[i] = i; 1610 address = reinterpret_cast<uint8_t*>(Heap::reallocate<DynamicallySizedObject>(address, 100000)); 1611 for (int i = 0; i < 100; i++) 1612 EXPECT_EQ(address[i], i); 1613 address = reinterpret_cast<uint8_t*>(Heap::reallocate<DynamicallySizedObject>(address, 50)); 1614 for (int i = 0; i < 50; i++) 1615 EXPECT_EQ(address[i], i); 1616 // This should be equivalent to free(address). 1617 EXPECT_EQ(reinterpret_cast<uintptr_t>(Heap::reallocate<DynamicallySizedObject>(address, 0)), 0ul); 1618 // This should be equivalent to malloc(0). 1619 EXPECT_EQ(reinterpret_cast<uintptr_t>(Heap::reallocate<DynamicallySizedObject>(0, 0)), 0ul); 1620 } 1621 1622 TEST(HeapTest, SimpleAllocation) 1623 { 1624 HeapStats initialHeapStats; 1625 clearOutOldGarbage(&initialHeapStats); 1626 EXPECT_EQ(0ul, initialHeapStats.totalObjectSpace()); 1627 1628 // Allocate an object in the heap. 1629 HeapAllocatedArray* array = new HeapAllocatedArray(); 1630 HeapStats statsAfterAllocation; 1631 getHeapStats(&statsAfterAllocation); 1632 EXPECT_TRUE(statsAfterAllocation.totalObjectSpace() >= sizeof(HeapAllocatedArray)); 1633 1634 // Sanity check of the contents in the heap. 1635 EXPECT_EQ(0, array->at(0)); 1636 EXPECT_EQ(42, array->at(42)); 1637 EXPECT_EQ(0, array->at(128)); 1638 EXPECT_EQ(999 % 128, array->at(999)); 1639 } 1640 1641 TEST(HeapTest, SimplePersistent) 1642 { 1643 Persistent<TraceCounter> traceCounter = TraceCounter::create(); 1644 EXPECT_EQ(0, traceCounter->traceCount()); 1645 1646 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1647 EXPECT_EQ(1, traceCounter->traceCount()); 1648 1649 Persistent<ClassWithMember> classWithMember = ClassWithMember::create(); 1650 EXPECT_EQ(0, classWithMember->traceCount()); 1651 1652 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1653 EXPECT_EQ(1, classWithMember->traceCount()); 1654 EXPECT_EQ(2, traceCounter->traceCount()); 1655 } 1656 1657 TEST(HeapTest, SimpleFinalization) 1658 { 1659 { 1660 Persistent<SimpleFinalizedObject> finalized = SimpleFinalizedObject::create(); 1661 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls); 1662 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1663 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls); 1664 } 1665 1666 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1667 EXPECT_EQ(1, SimpleFinalizedObject::s_destructorCalls); 1668 } 1669 1670 TEST(HeapTest, Finalization) 1671 { 1672 { 1673 HeapTestSubClass* t1 = HeapTestSubClass::create(); 1674 HeapTestSubClass* t2 = HeapTestSubClass::create(); 1675 HeapTestSuperClass* t3 = HeapTestSuperClass::create(); 1676 // FIXME(oilpan): Ignore unused variables. 1677 (void)t1; 1678 (void)t2; 1679 (void)t3; 1680 } 1681 // Nothing is marked so the GC should free everything and call 1682 // the finalizer on all three objects. 1683 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1684 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls); 1685 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls); 1686 // Destructors not called again when GCing again. 1687 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1688 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls); 1689 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls); 1690 } 1691 1692 TEST(HeapTest, TypedHeapSanity) 1693 { 1694 // We use TraceCounter for allocating an object on the general heap. 1695 Persistent<TraceCounter> generalHeapObject = TraceCounter::create(); 1696 Persistent<Node> typedHeapObject = Node::create(0); 1697 EXPECT_NE(pageHeaderFromObject(generalHeapObject.get()), 1698 pageHeaderFromObject(typedHeapObject.get())); 1699 } 1700 1701 TEST(HeapTest, NoAllocation) 1702 { 1703 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed()); 1704 { 1705 // Disallow allocation 1706 NoAllocationScope<AnyThread> noAllocationScope; 1707 EXPECT_FALSE(ThreadState::current()->isAllocationAllowed()); 1708 } 1709 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed()); 1710 } 1711 1712 TEST(HeapTest, Members) 1713 { 1714 Bar::s_live = 0; 1715 { 1716 Persistent<Baz> h1; 1717 Persistent<Baz> h2; 1718 { 1719 h1 = Baz::create(Bar::create()); 1720 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1721 EXPECT_EQ(1u, Bar::s_live); 1722 h2 = Baz::create(Bar::create()); 1723 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1724 EXPECT_EQ(2u, Bar::s_live); 1725 } 1726 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1727 EXPECT_EQ(2u, Bar::s_live); 1728 h1->clear(); 1729 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1730 EXPECT_EQ(1u, Bar::s_live); 1731 } 1732 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1733 EXPECT_EQ(0u, Bar::s_live); 1734 } 1735 1736 TEST(HeapTest, MarkTest) 1737 { 1738 { 1739 Bar::s_live = 0; 1740 Persistent<Bar> bar = Bar::create(); 1741 EXPECT_TRUE(ThreadState::current()->contains(bar)); 1742 EXPECT_EQ(1u, Bar::s_live); 1743 { 1744 Foo* foo = Foo::create(bar); 1745 EXPECT_TRUE(ThreadState::current()->contains(foo)); 1746 EXPECT_EQ(2u, Bar::s_live); 1747 EXPECT_TRUE(reinterpret_cast<Address>(foo) != reinterpret_cast<Address>(bar.get())); 1748 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 1749 EXPECT_TRUE(foo != bar); // To make sure foo is kept alive. 1750 EXPECT_EQ(2u, Bar::s_live); 1751 } 1752 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1753 EXPECT_EQ(1u, Bar::s_live); 1754 } 1755 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1756 EXPECT_EQ(0u, Bar::s_live); 1757 } 1758 1759 TEST(HeapTest, DeepTest) 1760 { 1761 const unsigned depth = 100000; 1762 Bar::s_live = 0; 1763 { 1764 Bar* bar = Bar::create(); 1765 EXPECT_TRUE(ThreadState::current()->contains(bar)); 1766 Foo* foo = Foo::create(bar); 1767 EXPECT_TRUE(ThreadState::current()->contains(foo)); 1768 EXPECT_EQ(2u, Bar::s_live); 1769 for (unsigned i = 0; i < depth; i++) { 1770 Foo* foo2 = Foo::create(foo); 1771 foo = foo2; 1772 EXPECT_TRUE(ThreadState::current()->contains(foo)); 1773 } 1774 EXPECT_EQ(depth + 2, Bar::s_live); 1775 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 1776 EXPECT_TRUE(foo != bar); // To make sure foo and bar are kept alive. 1777 EXPECT_EQ(depth + 2, Bar::s_live); 1778 } 1779 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1780 EXPECT_EQ(0u, Bar::s_live); 1781 } 1782 1783 TEST(HeapTest, WideTest) 1784 { 1785 Bar::s_live = 0; 1786 { 1787 Bars* bars = Bars::create(); 1788 unsigned width = Bars::width; 1789 EXPECT_EQ(width + 1, Bar::s_live); 1790 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 1791 EXPECT_EQ(width + 1, Bar::s_live); 1792 // Use bars here to make sure that it will be on the stack 1793 // for the conservative stack scan to find. 1794 EXPECT_EQ(width, bars->getWidth()); 1795 } 1796 EXPECT_EQ(Bars::width + 1, Bar::s_live); 1797 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1798 EXPECT_EQ(0u, Bar::s_live); 1799 } 1800 1801 TEST(HeapTest, HashMapOfMembers) 1802 { 1803 HeapStats initialHeapSize; 1804 IntWrapper::s_destructorCalls = 0; 1805 1806 clearOutOldGarbage(&initialHeapSize); 1807 { 1808 typedef HeapHashMap< 1809 Member<IntWrapper>, 1810 Member<IntWrapper>, 1811 DefaultHash<Member<IntWrapper> >::Hash, 1812 HashTraits<Member<IntWrapper> >, 1813 HashTraits<Member<IntWrapper> > > HeapObjectIdentityMap; 1814 1815 Persistent<HeapObjectIdentityMap> map = new HeapObjectIdentityMap(); 1816 1817 map->clear(); 1818 HeapStats afterSetWasCreated; 1819 getHeapStats(&afterSetWasCreated); 1820 EXPECT_TRUE(afterSetWasCreated.totalObjectSpace() > initialHeapSize.totalObjectSpace()); 1821 1822 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1823 HeapStats afterGC; 1824 getHeapStats(&afterGC); 1825 EXPECT_EQ(afterGC.totalObjectSpace(), afterSetWasCreated.totalObjectSpace()); 1826 1827 // If the additions below cause garbage collections, these 1828 // pointers should be found by conservative stack scanning. 1829 IntWrapper* one(IntWrapper::create(1)); 1830 IntWrapper* anotherOne(IntWrapper::create(1)); 1831 1832 map->add(one, one); 1833 1834 HeapStats afterOneAdd; 1835 getHeapStats(&afterOneAdd); 1836 EXPECT_TRUE(afterOneAdd.totalObjectSpace() > afterGC.totalObjectSpace()); 1837 1838 HeapObjectIdentityMap::iterator it(map->begin()); 1839 HeapObjectIdentityMap::iterator it2(map->begin()); 1840 ++it; 1841 ++it2; 1842 1843 map->add(anotherOne, one); 1844 1845 // The addition above can cause an allocation of a new 1846 // backing store. We therefore garbage collect before 1847 // taking the heap stats in order to get rid of the old 1848 // backing store. We make sure to not use conservative 1849 // stack scanning as that could find a pointer to the 1850 // old backing. 1851 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1852 HeapStats afterAddAndGC; 1853 getHeapStats(&afterAddAndGC); 1854 EXPECT_TRUE(afterAddAndGC.totalObjectSpace() >= afterOneAdd.totalObjectSpace()); 1855 1856 EXPECT_EQ(map->size(), 2u); // Two different wrappings of '1' are distinct. 1857 1858 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1859 EXPECT_TRUE(map->contains(one)); 1860 EXPECT_TRUE(map->contains(anotherOne)); 1861 1862 IntWrapper* gotten(map->get(one)); 1863 EXPECT_EQ(gotten->value(), one->value()); 1864 EXPECT_EQ(gotten, one); 1865 1866 HeapStats afterGC2; 1867 getHeapStats(&afterGC2); 1868 EXPECT_EQ(afterGC2.totalObjectSpace(), afterAddAndGC.totalObjectSpace()); 1869 1870 IntWrapper* dozen = 0; 1871 1872 for (int i = 1; i < 1000; i++) { // 999 iterations. 1873 IntWrapper* iWrapper(IntWrapper::create(i)); 1874 IntWrapper* iSquared(IntWrapper::create(i * i)); 1875 map->add(iWrapper, iSquared); 1876 if (i == 12) 1877 dozen = iWrapper; 1878 } 1879 HeapStats afterAdding1000; 1880 getHeapStats(&afterAdding1000); 1881 EXPECT_TRUE(afterAdding1000.totalObjectSpace() > afterGC2.totalObjectSpace()); 1882 1883 IntWrapper* gross(map->get(dozen)); 1884 EXPECT_EQ(gross->value(), 144); 1885 1886 // This should clear out any junk backings created by all the adds. 1887 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1888 HeapStats afterGC3; 1889 getHeapStats(&afterGC3); 1890 EXPECT_TRUE(afterGC3.totalObjectSpace() <= afterAdding1000.totalObjectSpace()); 1891 } 1892 1893 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1894 // The objects 'one', anotherOne, and the 999 other pairs. 1895 EXPECT_EQ(IntWrapper::s_destructorCalls, 2000); 1896 HeapStats afterGC4; 1897 getHeapStats(&afterGC4); 1898 EXPECT_EQ(afterGC4.totalObjectSpace(), initialHeapSize.totalObjectSpace()); 1899 } 1900 1901 TEST(HeapTest, NestedAllocation) 1902 { 1903 HeapStats initialHeapSize; 1904 clearOutOldGarbage(&initialHeapSize); 1905 { 1906 Persistent<ConstructorAllocation> constructorAllocation = ConstructorAllocation::create(); 1907 } 1908 HeapStats afterFree; 1909 clearOutOldGarbage(&afterFree); 1910 EXPECT_TRUE(initialHeapSize == afterFree); 1911 } 1912 1913 TEST(HeapTest, LargeObjects) 1914 { 1915 HeapStats initialHeapSize; 1916 clearOutOldGarbage(&initialHeapSize); 1917 IntWrapper::s_destructorCalls = 0; 1918 LargeObject::s_destructorCalls = 0; 1919 { 1920 int slack = 8; // LargeObject points to an IntWrapper that is also allocated. 1921 Persistent<LargeObject> object = LargeObject::create(); 1922 EXPECT_TRUE(ThreadState::current()->contains(object)); 1923 EXPECT_TRUE(ThreadState::current()->contains(reinterpret_cast<char*>(object.get()) + sizeof(LargeObject) - 1)); 1924 #if ENABLE(GC_PROFILE_MARKING) 1925 const GCInfo* info = ThreadState::current()->findGCInfo(reinterpret_cast<Address>(object.get())); 1926 EXPECT_NE(reinterpret_cast<const GCInfo*>(0), info); 1927 EXPECT_EQ(info, ThreadState::current()->findGCInfo(reinterpret_cast<Address>(object.get()) + sizeof(LargeObject) - 1)); 1928 EXPECT_NE(info, ThreadState::current()->findGCInfo(reinterpret_cast<Address>(object.get()) + sizeof(LargeObject))); 1929 EXPECT_NE(info, ThreadState::current()->findGCInfo(reinterpret_cast<Address>(object.get()) - 1)); 1930 #endif 1931 HeapStats afterAllocation; 1932 clearOutOldGarbage(&afterAllocation); 1933 { 1934 object->set(0, 'a'); 1935 EXPECT_EQ('a', object->get(0)); 1936 object->set(object->length() - 1, 'b'); 1937 EXPECT_EQ('b', object->get(object->length() - 1)); 1938 size_t expectedObjectSpace = sizeof(LargeObject) + sizeof(IntWrapper); 1939 size_t actualObjectSpace = 1940 afterAllocation.totalObjectSpace() - initialHeapSize.totalObjectSpace(); 1941 CheckWithSlack(expectedObjectSpace, actualObjectSpace, slack); 1942 // There is probably space for the IntWrapper in a heap page without 1943 // allocating extra pages. However, the IntWrapper allocation might cause 1944 // the addition of a heap page. 1945 size_t largeObjectAllocationSize = 1946 sizeof(LargeObject) + sizeof(LargeHeapObject<FinalizedHeapObjectHeader>) + sizeof(FinalizedHeapObjectHeader); 1947 size_t allocatedSpaceLowerBound = 1948 initialHeapSize.totalAllocatedSpace() + largeObjectAllocationSize; 1949 size_t allocatedSpaceUpperBound = allocatedSpaceLowerBound + slack + blinkPageSize; 1950 EXPECT_LE(allocatedSpaceLowerBound, afterAllocation.totalAllocatedSpace()); 1951 EXPECT_LE(afterAllocation.totalAllocatedSpace(), allocatedSpaceUpperBound); 1952 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 1953 EXPECT_EQ(0, LargeObject::s_destructorCalls); 1954 for (int i = 0; i < 10; i++) 1955 object = LargeObject::create(); 1956 } 1957 HeapStats oneLargeObject; 1958 clearOutOldGarbage(&oneLargeObject); 1959 EXPECT_TRUE(oneLargeObject == afterAllocation); 1960 EXPECT_EQ(10, IntWrapper::s_destructorCalls); 1961 EXPECT_EQ(10, LargeObject::s_destructorCalls); 1962 } 1963 HeapStats backToInitial; 1964 clearOutOldGarbage(&backToInitial); 1965 EXPECT_TRUE(initialHeapSize == backToInitial); 1966 EXPECT_EQ(11, IntWrapper::s_destructorCalls); 1967 EXPECT_EQ(11, LargeObject::s_destructorCalls); 1968 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1969 } 1970 1971 typedef std::pair<Member<IntWrapper>, int> PairWrappedUnwrapped; 1972 typedef std::pair<int, Member<IntWrapper> > PairUnwrappedWrapped; 1973 typedef std::pair<WeakMember<IntWrapper>, Member<IntWrapper> > PairWeakStrong; 1974 typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper> > PairStrongWeak; 1975 typedef std::pair<WeakMember<IntWrapper>, int> PairWeakUnwrapped; 1976 typedef std::pair<int, WeakMember<IntWrapper> > PairUnwrappedWeak; 1977 1978 class Container : public GarbageCollected<Container> { 1979 public: 1980 static Container* create() { return new Container(); } 1981 HeapHashMap<Member<IntWrapper>, Member<IntWrapper> > map; 1982 HeapHashSet<Member<IntWrapper> > set; 1983 HeapHashSet<Member<IntWrapper> > set2; 1984 HeapHashCountedSet<Member<IntWrapper> > set3; 1985 HeapVector<Member<IntWrapper>, 2> vector; 1986 HeapVector<PairWrappedUnwrapped, 2> vectorWU; 1987 HeapVector<PairUnwrappedWrapped, 2> vectorUW; 1988 HeapDeque<Member<IntWrapper>, 0> deque; 1989 HeapDeque<PairWrappedUnwrapped, 0> dequeWU; 1990 HeapDeque<PairUnwrappedWrapped, 0> dequeUW; 1991 void trace(Visitor* visitor) 1992 { 1993 visitor->trace(map); 1994 visitor->trace(set); 1995 visitor->trace(set2); 1996 visitor->trace(set3); 1997 visitor->trace(vector); 1998 visitor->trace(vectorWU); 1999 visitor->trace(vectorUW); 2000 visitor->trace(deque); 2001 visitor->trace(dequeWU); 2002 visitor->trace(dequeUW); 2003 } 2004 }; 2005 2006 struct ShouldBeTraced { 2007 explicit ShouldBeTraced(IntWrapper* wrapper) : m_wrapper(wrapper) { } 2008 void trace(Visitor* visitor) { visitor->trace(m_wrapper); } 2009 Member<IntWrapper> m_wrapper; 2010 }; 2011 2012 class OffHeapContainer : public GarbageCollectedFinalized<OffHeapContainer> { 2013 public: 2014 static OffHeapContainer* create() { return new OffHeapContainer(); } 2015 2016 static const int iterations = 300; 2017 static const int deadWrappers = 1200; 2018 2019 OffHeapContainer() 2020 { 2021 for (int i = 0; i < iterations; i++) { 2022 m_deque1.append(ShouldBeTraced(IntWrapper::create(i))); 2023 m_vector1.append(ShouldBeTraced(IntWrapper::create(i))); 2024 m_deque2.append(IntWrapper::create(i)); 2025 m_vector2.append(IntWrapper::create(i)); 2026 } 2027 2028 Deque<ShouldBeTraced>::iterator d1Iterator(m_deque1.begin()); 2029 Vector<ShouldBeTraced>::iterator v1Iterator(m_vector1.begin()); 2030 Deque<Member<IntWrapper> >::iterator d2Iterator(m_deque2.begin()); 2031 Vector<Member<IntWrapper> >::iterator v2Iterator(m_vector2.begin()); 2032 2033 for (int i = 0; i < iterations; i++) { 2034 EXPECT_EQ(i, m_vector1[i].m_wrapper->value()); 2035 EXPECT_EQ(i, m_vector2[i]->value()); 2036 EXPECT_EQ(i, d1Iterator->m_wrapper->value()); 2037 EXPECT_EQ(i, v1Iterator->m_wrapper->value()); 2038 EXPECT_EQ(i, d2Iterator->get()->value()); 2039 EXPECT_EQ(i, v2Iterator->get()->value()); 2040 ++d1Iterator; 2041 ++v1Iterator; 2042 ++d2Iterator; 2043 ++v2Iterator; 2044 } 2045 EXPECT_EQ(d1Iterator, m_deque1.end()); 2046 EXPECT_EQ(v1Iterator, m_vector1.end()); 2047 EXPECT_EQ(d2Iterator, m_deque2.end()); 2048 EXPECT_EQ(v2Iterator, m_vector2.end()); 2049 } 2050 2051 void trace(Visitor* visitor) 2052 { 2053 visitor->trace(m_deque1); 2054 visitor->trace(m_vector1); 2055 visitor->trace(m_deque2); 2056 visitor->trace(m_vector2); 2057 } 2058 2059 Deque<ShouldBeTraced> m_deque1; 2060 Vector<ShouldBeTraced> m_vector1; 2061 Deque<Member<IntWrapper> > m_deque2; 2062 Vector<Member<IntWrapper> > m_vector2; 2063 }; 2064 2065 const int OffHeapContainer::iterations; 2066 const int OffHeapContainer::deadWrappers; 2067 2068 // These class definitions test compile-time asserts with transition 2069 // types. They are therefore unused in test code and just need to 2070 // compile. This is intentional; do not delete the A and B classes below. 2071 class A : public WillBeGarbageCollectedMixin { 2072 }; 2073 2074 class B : public NoBaseWillBeGarbageCollected<B>, public A { 2075 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(B); 2076 public: 2077 void trace(Visitor*) { } 2078 }; 2079 2080 TEST(HeapTest, HeapVectorFilledWithValue) 2081 { 2082 IntWrapper* val = IntWrapper::create(1); 2083 HeapVector<Member<IntWrapper> > vector(10, val); 2084 EXPECT_EQ(10u, vector.size()); 2085 for (size_t i = 0; i < vector.size(); i++) 2086 EXPECT_EQ(val, vector[i]); 2087 } 2088 2089 TEST(HeapTest, HeapVectorWithInlineCapacity) 2090 { 2091 IntWrapper* one = IntWrapper::create(1); 2092 IntWrapper* two = IntWrapper::create(2); 2093 IntWrapper* three = IntWrapper::create(3); 2094 IntWrapper* four = IntWrapper::create(4); 2095 IntWrapper* five = IntWrapper::create(5); 2096 IntWrapper* six = IntWrapper::create(6); 2097 { 2098 HeapVector<Member<IntWrapper>, 2> vector; 2099 vector.append(one); 2100 vector.append(two); 2101 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 2102 EXPECT_TRUE(vector.contains(one)); 2103 EXPECT_TRUE(vector.contains(two)); 2104 2105 vector.append(three); 2106 vector.append(four); 2107 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 2108 EXPECT_TRUE(vector.contains(one)); 2109 EXPECT_TRUE(vector.contains(two)); 2110 EXPECT_TRUE(vector.contains(three)); 2111 EXPECT_TRUE(vector.contains(four)); 2112 2113 vector.shrink(1); 2114 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 2115 EXPECT_TRUE(vector.contains(one)); 2116 EXPECT_FALSE(vector.contains(two)); 2117 EXPECT_FALSE(vector.contains(three)); 2118 EXPECT_FALSE(vector.contains(four)); 2119 } 2120 { 2121 HeapVector<Member<IntWrapper>, 2> vector1; 2122 HeapVector<Member<IntWrapper>, 2> vector2; 2123 2124 vector1.append(one); 2125 vector2.append(two); 2126 vector1.swap(vector2); 2127 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 2128 EXPECT_TRUE(vector1.contains(two)); 2129 EXPECT_TRUE(vector2.contains(one)); 2130 } 2131 { 2132 HeapVector<Member<IntWrapper>, 2> vector1; 2133 HeapVector<Member<IntWrapper>, 2> vector2; 2134 2135 vector1.append(one); 2136 vector1.append(two); 2137 vector2.append(three); 2138 vector2.append(four); 2139 vector2.append(five); 2140 vector2.append(six); 2141 vector1.swap(vector2); 2142 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 2143 EXPECT_TRUE(vector1.contains(three)); 2144 EXPECT_TRUE(vector1.contains(four)); 2145 EXPECT_TRUE(vector1.contains(five)); 2146 EXPECT_TRUE(vector1.contains(six)); 2147 EXPECT_TRUE(vector2.contains(one)); 2148 EXPECT_TRUE(vector2.contains(two)); 2149 } 2150 } 2151 2152 template<typename T, size_t inlineCapacity, typename U> 2153 bool dequeContains(HeapDeque<T, inlineCapacity>& deque, U u) 2154 { 2155 typedef typename HeapDeque<T, inlineCapacity>::iterator iterator; 2156 for (iterator it = deque.begin(); it != deque.end(); ++it) { 2157 if (*it == u) 2158 return true; 2159 } 2160 return false; 2161 } 2162 2163 TEST(HeapTest, HeapCollectionTypes) 2164 { 2165 HeapStats initialHeapSize; 2166 IntWrapper::s_destructorCalls = 0; 2167 2168 typedef HeapHashMap<Member<IntWrapper>, Member<IntWrapper> > MemberMember; 2169 typedef HeapHashMap<Member<IntWrapper>, int> MemberPrimitive; 2170 typedef HeapHashMap<int, Member<IntWrapper> > PrimitiveMember; 2171 2172 typedef HeapHashSet<Member<IntWrapper> > MemberSet; 2173 typedef HeapHashCountedSet<Member<IntWrapper> > MemberCountedSet; 2174 2175 typedef HeapVector<Member<IntWrapper>, 2> MemberVector; 2176 typedef HeapDeque<Member<IntWrapper>, 0> MemberDeque; 2177 2178 typedef HeapVector<PairWrappedUnwrapped, 2> VectorWU; 2179 typedef HeapVector<PairUnwrappedWrapped, 2> VectorUW; 2180 typedef HeapDeque<PairWrappedUnwrapped, 0> DequeWU; 2181 typedef HeapDeque<PairUnwrappedWrapped, 0> DequeUW; 2182 2183 Persistent<MemberMember> memberMember = new MemberMember(); 2184 Persistent<MemberMember> memberMember2 = new MemberMember(); 2185 Persistent<MemberMember> memberMember3 = new MemberMember(); 2186 Persistent<MemberPrimitive> memberPrimitive = new MemberPrimitive(); 2187 Persistent<PrimitiveMember> primitiveMember = new PrimitiveMember(); 2188 Persistent<MemberSet> set = new MemberSet(); 2189 Persistent<MemberSet> set2 = new MemberSet(); 2190 Persistent<MemberCountedSet> set3 = new MemberCountedSet(); 2191 Persistent<MemberVector> vector = new MemberVector(); 2192 Persistent<MemberVector> vector2 = new MemberVector(); 2193 Persistent<VectorWU> vectorWU = new VectorWU(); 2194 Persistent<VectorWU> vectorWU2 = new VectorWU(); 2195 Persistent<VectorUW> vectorUW = new VectorUW(); 2196 Persistent<VectorUW> vectorUW2 = new VectorUW(); 2197 Persistent<MemberDeque> deque = new MemberDeque(); 2198 Persistent<MemberDeque> deque2 = new MemberDeque(); 2199 Persistent<DequeWU> dequeWU = new DequeWU(); 2200 Persistent<DequeWU> dequeWU2 = new DequeWU(); 2201 Persistent<DequeUW> dequeUW = new DequeUW(); 2202 Persistent<DequeUW> dequeUW2 = new DequeUW(); 2203 Persistent<Container> container = Container::create(); 2204 2205 clearOutOldGarbage(&initialHeapSize); 2206 { 2207 Persistent<IntWrapper> one(IntWrapper::create(1)); 2208 Persistent<IntWrapper> two(IntWrapper::create(2)); 2209 Persistent<IntWrapper> oneB(IntWrapper::create(1)); 2210 Persistent<IntWrapper> twoB(IntWrapper::create(2)); 2211 Persistent<IntWrapper> oneC(IntWrapper::create(1)); 2212 Persistent<IntWrapper> oneD(IntWrapper::create(1)); 2213 Persistent<IntWrapper> oneE(IntWrapper::create(1)); 2214 Persistent<IntWrapper> oneF(IntWrapper::create(1)); 2215 { 2216 IntWrapper* threeB(IntWrapper::create(3)); 2217 IntWrapper* threeC(IntWrapper::create(3)); 2218 IntWrapper* threeD(IntWrapper::create(3)); 2219 IntWrapper* threeE(IntWrapper::create(3)); 2220 IntWrapper* threeF(IntWrapper::create(3)); 2221 IntWrapper* three(IntWrapper::create(3)); 2222 IntWrapper* fourB(IntWrapper::create(4)); 2223 IntWrapper* fourC(IntWrapper::create(4)); 2224 IntWrapper* fourD(IntWrapper::create(4)); 2225 IntWrapper* fourE(IntWrapper::create(4)); 2226 IntWrapper* fourF(IntWrapper::create(4)); 2227 IntWrapper* four(IntWrapper::create(4)); 2228 IntWrapper* fiveC(IntWrapper::create(5)); 2229 IntWrapper* fiveD(IntWrapper::create(5)); 2230 IntWrapper* fiveE(IntWrapper::create(5)); 2231 IntWrapper* fiveF(IntWrapper::create(5)); 2232 2233 // Member Collections. 2234 memberMember2->add(one, two); 2235 memberMember2->add(two, three); 2236 memberMember2->add(three, four); 2237 memberMember2->add(four, one); 2238 primitiveMember->add(1, two); 2239 primitiveMember->add(2, three); 2240 primitiveMember->add(3, four); 2241 primitiveMember->add(4, one); 2242 memberPrimitive->add(one, 2); 2243 memberPrimitive->add(two, 3); 2244 memberPrimitive->add(three, 4); 2245 memberPrimitive->add(four, 1); 2246 set2->add(one); 2247 set2->add(two); 2248 set2->add(three); 2249 set2->add(four); 2250 set->add(oneB); 2251 set3->add(oneB); 2252 set3->add(oneB); 2253 vector->append(oneB); 2254 deque->append(oneB); 2255 vector2->append(threeB); 2256 vector2->append(fourB); 2257 deque2->append(threeE); 2258 deque2->append(fourE); 2259 vectorWU->append(PairWrappedUnwrapped(&*oneC, 42)); 2260 dequeWU->append(PairWrappedUnwrapped(&*oneE, 42)); 2261 vectorWU2->append(PairWrappedUnwrapped(&*threeC, 43)); 2262 vectorWU2->append(PairWrappedUnwrapped(&*fourC, 44)); 2263 vectorWU2->append(PairWrappedUnwrapped(&*fiveC, 45)); 2264 dequeWU2->append(PairWrappedUnwrapped(&*threeE, 43)); 2265 dequeWU2->append(PairWrappedUnwrapped(&*fourE, 44)); 2266 dequeWU2->append(PairWrappedUnwrapped(&*fiveE, 45)); 2267 vectorUW->append(PairUnwrappedWrapped(1, &*oneD)); 2268 vectorUW2->append(PairUnwrappedWrapped(103, &*threeD)); 2269 vectorUW2->append(PairUnwrappedWrapped(104, &*fourD)); 2270 vectorUW2->append(PairUnwrappedWrapped(105, &*fiveD)); 2271 dequeUW->append(PairUnwrappedWrapped(1, &*oneF)); 2272 dequeUW2->append(PairUnwrappedWrapped(103, &*threeF)); 2273 dequeUW2->append(PairUnwrappedWrapped(104, &*fourF)); 2274 dequeUW2->append(PairUnwrappedWrapped(105, &*fiveF)); 2275 2276 EXPECT_TRUE(dequeContains(*deque, oneB)); 2277 2278 // Collect garbage. This should change nothing since we are keeping 2279 // alive the IntWrapper objects with on-stack pointers. 2280 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 2281 2282 EXPECT_TRUE(dequeContains(*deque, oneB)); 2283 2284 EXPECT_EQ(0u, memberMember->size()); 2285 EXPECT_EQ(4u, memberMember2->size()); 2286 EXPECT_EQ(4u, primitiveMember->size()); 2287 EXPECT_EQ(4u, memberPrimitive->size()); 2288 EXPECT_EQ(1u, set->size()); 2289 EXPECT_EQ(4u, set2->size()); 2290 EXPECT_EQ(1u, set3->size()); 2291 EXPECT_EQ(1u, vector->size()); 2292 EXPECT_EQ(2u, vector2->size()); 2293 EXPECT_EQ(1u, vectorWU->size()); 2294 EXPECT_EQ(3u, vectorWU2->size()); 2295 EXPECT_EQ(1u, vectorUW->size()); 2296 EXPECT_EQ(3u, vectorUW2->size()); 2297 EXPECT_EQ(1u, deque->size()); 2298 EXPECT_EQ(2u, deque2->size()); 2299 EXPECT_EQ(1u, dequeWU->size()); 2300 EXPECT_EQ(3u, dequeWU2->size()); 2301 EXPECT_EQ(1u, dequeUW->size()); 2302 EXPECT_EQ(3u, dequeUW2->size()); 2303 2304 MemberVector& cvec = container->vector; 2305 cvec.swap(*vector.get()); 2306 vector2->swap(cvec); 2307 vector->swap(cvec); 2308 2309 VectorWU& cvecWU = container->vectorWU; 2310 cvecWU.swap(*vectorWU.get()); 2311 vectorWU2->swap(cvecWU); 2312 vectorWU->swap(cvecWU); 2313 2314 VectorUW& cvecUW = container->vectorUW; 2315 cvecUW.swap(*vectorUW.get()); 2316 vectorUW2->swap(cvecUW); 2317 vectorUW->swap(cvecUW); 2318 2319 MemberDeque& cDeque = container->deque; 2320 cDeque.swap(*deque.get()); 2321 deque2->swap(cDeque); 2322 deque->swap(cDeque); 2323 2324 DequeWU& cDequeWU = container->dequeWU; 2325 cDequeWU.swap(*dequeWU.get()); 2326 dequeWU2->swap(cDequeWU); 2327 dequeWU->swap(cDequeWU); 2328 2329 DequeUW& cDequeUW = container->dequeUW; 2330 cDequeUW.swap(*dequeUW.get()); 2331 dequeUW2->swap(cDequeUW); 2332 dequeUW->swap(cDequeUW); 2333 2334 // Swap set and set2 in a roundabout way. 2335 MemberSet& cset1 = container->set; 2336 MemberSet& cset2 = container->set2; 2337 set->swap(cset1); 2338 set2->swap(cset2); 2339 set->swap(cset2); 2340 cset1.swap(cset2); 2341 cset2.swap(set2); 2342 2343 MemberCountedSet& cCountedSet = container->set3; 2344 set3->swap(cCountedSet); 2345 EXPECT_EQ(0u, set3->size()); 2346 set3->swap(cCountedSet); 2347 2348 // Triple swap. 2349 container->map.swap(memberMember2); 2350 MemberMember& containedMap = container->map; 2351 memberMember3->swap(containedMap); 2352 memberMember3->swap(memberMember); 2353 2354 EXPECT_TRUE(memberMember->get(one) == two); 2355 EXPECT_TRUE(memberMember->get(two) == three); 2356 EXPECT_TRUE(memberMember->get(three) == four); 2357 EXPECT_TRUE(memberMember->get(four) == one); 2358 EXPECT_TRUE(primitiveMember->get(1) == two); 2359 EXPECT_TRUE(primitiveMember->get(2) == three); 2360 EXPECT_TRUE(primitiveMember->get(3) == four); 2361 EXPECT_TRUE(primitiveMember->get(4) == one); 2362 EXPECT_EQ(1, memberPrimitive->get(four)); 2363 EXPECT_EQ(2, memberPrimitive->get(one)); 2364 EXPECT_EQ(3, memberPrimitive->get(two)); 2365 EXPECT_EQ(4, memberPrimitive->get(three)); 2366 EXPECT_TRUE(set->contains(one)); 2367 EXPECT_TRUE(set->contains(two)); 2368 EXPECT_TRUE(set->contains(three)); 2369 EXPECT_TRUE(set->contains(four)); 2370 EXPECT_TRUE(set2->contains(oneB)); 2371 EXPECT_TRUE(set3->contains(oneB)); 2372 EXPECT_TRUE(vector->contains(threeB)); 2373 EXPECT_TRUE(vector->contains(fourB)); 2374 EXPECT_TRUE(dequeContains(*deque, threeE)); 2375 EXPECT_TRUE(dequeContains(*deque, fourE)); 2376 EXPECT_TRUE(vector2->contains(oneB)); 2377 EXPECT_FALSE(vector2->contains(threeB)); 2378 EXPECT_TRUE(dequeContains(*deque2, oneB)); 2379 EXPECT_FALSE(dequeContains(*deque2, threeE)); 2380 EXPECT_TRUE(vectorWU->contains(PairWrappedUnwrapped(&*threeC, 43))); 2381 EXPECT_TRUE(vectorWU->contains(PairWrappedUnwrapped(&*fourC, 44))); 2382 EXPECT_TRUE(vectorWU->contains(PairWrappedUnwrapped(&*fiveC, 45))); 2383 EXPECT_TRUE(vectorWU2->contains(PairWrappedUnwrapped(&*oneC, 42))); 2384 EXPECT_FALSE(vectorWU2->contains(PairWrappedUnwrapped(&*threeC, 43))); 2385 EXPECT_TRUE(vectorUW->contains(PairUnwrappedWrapped(103, &*threeD))); 2386 EXPECT_TRUE(vectorUW->contains(PairUnwrappedWrapped(104, &*fourD))); 2387 EXPECT_TRUE(vectorUW->contains(PairUnwrappedWrapped(105, &*fiveD))); 2388 EXPECT_TRUE(vectorUW2->contains(PairUnwrappedWrapped(1, &*oneD))); 2389 EXPECT_FALSE(vectorUW2->contains(PairUnwrappedWrapped(103, &*threeD))); 2390 EXPECT_TRUE(dequeContains(*dequeWU, PairWrappedUnwrapped(&*threeE, 43))); 2391 EXPECT_TRUE(dequeContains(*dequeWU, PairWrappedUnwrapped(&*fourE, 44))); 2392 EXPECT_TRUE(dequeContains(*dequeWU, PairWrappedUnwrapped(&*fiveE, 45))); 2393 EXPECT_TRUE(dequeContains(*dequeWU2, PairWrappedUnwrapped(&*oneE, 42))); 2394 EXPECT_FALSE(dequeContains(*dequeWU2, PairWrappedUnwrapped(&*threeE, 43))); 2395 EXPECT_TRUE(dequeContains(*dequeUW, PairUnwrappedWrapped(103, &*threeF))); 2396 EXPECT_TRUE(dequeContains(*dequeUW, PairUnwrappedWrapped(104, &*fourF))); 2397 EXPECT_TRUE(dequeContains(*dequeUW, PairUnwrappedWrapped(105, &*fiveF))); 2398 EXPECT_TRUE(dequeContains(*dequeUW2, PairUnwrappedWrapped(1, &*oneF))); 2399 EXPECT_FALSE(dequeContains(*dequeUW2, PairUnwrappedWrapped(103, &*threeF))); 2400 } 2401 2402 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2403 2404 EXPECT_EQ(4u, memberMember->size()); 2405 EXPECT_EQ(0u, memberMember2->size()); 2406 EXPECT_EQ(4u, primitiveMember->size()); 2407 EXPECT_EQ(4u, memberPrimitive->size()); 2408 EXPECT_EQ(4u, set->size()); 2409 EXPECT_EQ(1u, set2->size()); 2410 EXPECT_EQ(1u, set3->size()); 2411 EXPECT_EQ(2u, vector->size()); 2412 EXPECT_EQ(1u, vector2->size()); 2413 EXPECT_EQ(3u, vectorUW->size()); 2414 EXPECT_EQ(1u, vector2->size()); 2415 EXPECT_EQ(2u, deque->size()); 2416 EXPECT_EQ(1u, deque2->size()); 2417 EXPECT_EQ(3u, dequeUW->size()); 2418 EXPECT_EQ(1u, deque2->size()); 2419 2420 EXPECT_TRUE(memberMember->get(one) == two); 2421 EXPECT_TRUE(primitiveMember->get(1) == two); 2422 EXPECT_TRUE(primitiveMember->get(4) == one); 2423 EXPECT_EQ(2, memberPrimitive->get(one)); 2424 EXPECT_EQ(3, memberPrimitive->get(two)); 2425 EXPECT_TRUE(set->contains(one)); 2426 EXPECT_TRUE(set->contains(two)); 2427 EXPECT_FALSE(set->contains(oneB)); 2428 EXPECT_TRUE(set2->contains(oneB)); 2429 EXPECT_TRUE(set3->contains(oneB)); 2430 EXPECT_EQ(2u, set3->find(oneB)->value); 2431 EXPECT_EQ(3, vector->at(0)->value()); 2432 EXPECT_EQ(4, vector->at(1)->value()); 2433 EXPECT_EQ(3, deque->begin()->get()->value()); 2434 } 2435 2436 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2437 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2438 2439 EXPECT_EQ(4u, memberMember->size()); 2440 EXPECT_EQ(4u, primitiveMember->size()); 2441 EXPECT_EQ(4u, memberPrimitive->size()); 2442 EXPECT_EQ(4u, set->size()); 2443 EXPECT_EQ(1u, set2->size()); 2444 EXPECT_EQ(2u, vector->size()); 2445 EXPECT_EQ(1u, vector2->size()); 2446 EXPECT_EQ(3u, vectorWU->size()); 2447 EXPECT_EQ(1u, vectorWU2->size()); 2448 EXPECT_EQ(3u, vectorUW->size()); 2449 EXPECT_EQ(1u, vectorUW2->size()); 2450 EXPECT_EQ(2u, deque->size()); 2451 EXPECT_EQ(1u, deque2->size()); 2452 EXPECT_EQ(3u, dequeWU->size()); 2453 EXPECT_EQ(1u, dequeWU2->size()); 2454 EXPECT_EQ(3u, dequeUW->size()); 2455 EXPECT_EQ(1u, dequeUW2->size()); 2456 } 2457 2458 template<typename T> 2459 void MapIteratorCheck(T& it, const T& end, int expected) 2460 { 2461 int found = 0; 2462 while (it != end) { 2463 found++; 2464 int key = it->key->value(); 2465 int value = it->value->value(); 2466 EXPECT_TRUE(key >= 0 && key < 1100); 2467 EXPECT_TRUE(value >= 0 && value < 1100); 2468 ++it; 2469 } 2470 EXPECT_EQ(expected, found); 2471 } 2472 2473 template<typename T> 2474 void SetIteratorCheck(T& it, const T& end, int expected) 2475 { 2476 int found = 0; 2477 while (it != end) { 2478 found++; 2479 int value = (*it)->value(); 2480 EXPECT_TRUE(value >= 0 && value < 1100); 2481 ++it; 2482 } 2483 EXPECT_EQ(expected, found); 2484 } 2485 2486 TEST(HeapTest, HeapWeakCollectionSimple) 2487 { 2488 HeapStats initialHeapStats; 2489 clearOutOldGarbage(&initialHeapStats); 2490 IntWrapper::s_destructorCalls = 0; 2491 2492 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive; 2493 2494 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong; 2495 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak; 2496 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWeak; 2497 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet; 2498 typedef HeapHashCountedSet<WeakMember<IntWrapper> > WeakCountedSet; 2499 2500 Persistent<WeakStrong> weakStrong = new WeakStrong(); 2501 Persistent<StrongWeak> strongWeak = new StrongWeak(); 2502 Persistent<WeakWeak> weakWeak = new WeakWeak(); 2503 Persistent<WeakSet> weakSet = new WeakSet(); 2504 Persistent<WeakCountedSet> weakCountedSet = new WeakCountedSet(); 2505 2506 Persistent<IntWrapper> two = IntWrapper::create(2); 2507 2508 keepNumbersAlive.append(IntWrapper::create(103)); 2509 keepNumbersAlive.append(IntWrapper::create(10)); 2510 2511 { 2512 weakStrong->add(IntWrapper::create(1), two); 2513 strongWeak->add(two, IntWrapper::create(1)); 2514 weakWeak->add(two, IntWrapper::create(42)); 2515 weakWeak->add(IntWrapper::create(42), two); 2516 weakSet->add(IntWrapper::create(0)); 2517 weakSet->add(two); 2518 weakSet->add(keepNumbersAlive[0]); 2519 weakSet->add(keepNumbersAlive[1]); 2520 weakCountedSet->add(IntWrapper::create(0)); 2521 weakCountedSet->add(two); 2522 weakCountedSet->add(two); 2523 weakCountedSet->add(two); 2524 weakCountedSet->add(keepNumbersAlive[0]); 2525 weakCountedSet->add(keepNumbersAlive[1]); 2526 EXPECT_EQ(1u, weakStrong->size()); 2527 EXPECT_EQ(1u, strongWeak->size()); 2528 EXPECT_EQ(2u, weakWeak->size()); 2529 EXPECT_EQ(4u, weakSet->size()); 2530 EXPECT_EQ(4u, weakCountedSet->size()); 2531 EXPECT_EQ(3u, weakCountedSet->find(two)->value); 2532 weakCountedSet->remove(two); 2533 EXPECT_EQ(2u, weakCountedSet->find(two)->value); 2534 } 2535 2536 keepNumbersAlive[0] = nullptr; 2537 2538 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2539 2540 EXPECT_EQ(0u, weakStrong->size()); 2541 EXPECT_EQ(0u, strongWeak->size()); 2542 EXPECT_EQ(0u, weakWeak->size()); 2543 EXPECT_EQ(2u, weakSet->size()); 2544 EXPECT_EQ(2u, weakCountedSet->size()); 2545 } 2546 2547 template<typename Set> 2548 void orderedSetHelper(bool strong) 2549 { 2550 HeapStats initialHeapStats; 2551 clearOutOldGarbage(&initialHeapStats); 2552 IntWrapper::s_destructorCalls = 0; 2553 2554 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive; 2555 2556 Persistent<Set> set1 = new Set(); 2557 Persistent<Set> set2 = new Set(); 2558 2559 const Set& constSet = *set1.get(); 2560 2561 keepNumbersAlive.append(IntWrapper::create(2)); 2562 keepNumbersAlive.append(IntWrapper::create(103)); 2563 keepNumbersAlive.append(IntWrapper::create(10)); 2564 2565 set1->add(IntWrapper::create(0)); 2566 set1->add(keepNumbersAlive[0]); 2567 set1->add(keepNumbersAlive[1]); 2568 set1->add(keepNumbersAlive[2]); 2569 2570 set2->clear(); 2571 set2->add(IntWrapper::create(42)); 2572 set2->clear(); 2573 2574 EXPECT_EQ(4u, set1->size()); 2575 typename Set::iterator it(set1->begin()); 2576 typename Set::reverse_iterator reverse(set1->rbegin()); 2577 typename Set::const_iterator cit(constSet.begin()); 2578 typename Set::const_reverse_iterator creverse(constSet.rbegin()); 2579 2580 EXPECT_EQ(0, (*it)->value()); 2581 EXPECT_EQ(0, (*cit)->value()); 2582 ++it; 2583 ++cit; 2584 EXPECT_EQ(2, (*it)->value()); 2585 EXPECT_EQ(2, (*cit)->value()); 2586 --it; 2587 --cit; 2588 EXPECT_EQ(0, (*it)->value()); 2589 EXPECT_EQ(0, (*cit)->value()); 2590 ++it; 2591 ++cit; 2592 ++it; 2593 ++cit; 2594 EXPECT_EQ(103, (*it)->value()); 2595 EXPECT_EQ(103, (*cit)->value()); 2596 ++it; 2597 ++cit; 2598 EXPECT_EQ(10, (*it)->value()); 2599 EXPECT_EQ(10, (*cit)->value()); 2600 ++it; 2601 ++cit; 2602 2603 EXPECT_EQ(10, (*reverse)->value()); 2604 EXPECT_EQ(10, (*creverse)->value()); 2605 ++reverse; 2606 ++creverse; 2607 EXPECT_EQ(103, (*reverse)->value()); 2608 EXPECT_EQ(103, (*creverse)->value()); 2609 --reverse; 2610 --creverse; 2611 EXPECT_EQ(10, (*reverse)->value()); 2612 EXPECT_EQ(10, (*creverse)->value()); 2613 ++reverse; 2614 ++creverse; 2615 ++reverse; 2616 ++creverse; 2617 EXPECT_EQ(2, (*reverse)->value()); 2618 EXPECT_EQ(2, (*creverse)->value()); 2619 ++reverse; 2620 ++creverse; 2621 EXPECT_EQ(0, (*reverse)->value()); 2622 EXPECT_EQ(0, (*creverse)->value()); 2623 ++reverse; 2624 ++creverse; 2625 2626 EXPECT_EQ(set1->end(), it); 2627 EXPECT_EQ(constSet.end(), cit); 2628 EXPECT_EQ(set1->rend(), reverse); 2629 EXPECT_EQ(constSet.rend(), creverse); 2630 2631 typename Set::iterator iX(set2->begin()); 2632 EXPECT_EQ(set2->end(), iX); 2633 2634 if (strong) 2635 set1->remove(keepNumbersAlive[0]); 2636 2637 keepNumbersAlive[0] = nullptr; 2638 2639 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2640 2641 EXPECT_EQ(2u + (strong ? 1u : 0u), set1->size()); 2642 2643 EXPECT_EQ(2 + (strong ? 0 : 1), IntWrapper::s_destructorCalls); 2644 2645 typename Set::iterator i2(set1->begin()); 2646 if (strong) { 2647 EXPECT_EQ(0, (*i2)->value()); 2648 ++i2; 2649 EXPECT_NE(set1->end(), i2); 2650 } 2651 EXPECT_EQ(103, (*i2)->value()); 2652 ++i2; 2653 EXPECT_NE(set1->end(), i2); 2654 EXPECT_EQ(10, (*i2)->value()); 2655 ++i2; 2656 EXPECT_EQ(set1->end(), i2); 2657 } 2658 2659 TEST(HeapTest, HeapWeakLinkedHashSet) 2660 { 2661 orderedSetHelper<HeapLinkedHashSet<Member<IntWrapper> > >(true); 2662 orderedSetHelper<HeapLinkedHashSet<WeakMember<IntWrapper> > >(false); 2663 orderedSetHelper<HeapListHashSet<Member<IntWrapper> > >(true); 2664 } 2665 2666 class ThingWithDestructor { 2667 public: 2668 ThingWithDestructor() 2669 : m_x(emptyValue) 2670 { 2671 s_liveThingsWithDestructor++; 2672 } 2673 2674 ThingWithDestructor(int x) 2675 : m_x(x) 2676 { 2677 s_liveThingsWithDestructor++; 2678 } 2679 2680 ThingWithDestructor(const ThingWithDestructor&other) 2681 { 2682 *this = other; 2683 s_liveThingsWithDestructor++; 2684 } 2685 2686 ~ThingWithDestructor() 2687 { 2688 s_liveThingsWithDestructor--; 2689 } 2690 2691 int value() { return m_x; } 2692 2693 static int s_liveThingsWithDestructor; 2694 2695 unsigned hash() { return IntHash<int>::hash(m_x); } 2696 2697 private: 2698 static const int emptyValue = 0; 2699 int m_x; 2700 }; 2701 2702 int ThingWithDestructor::s_liveThingsWithDestructor; 2703 2704 struct ThingWithDestructorTraits : public HashTraits<ThingWithDestructor> { 2705 static const bool needsDestruction = true; 2706 }; 2707 2708 static void heapMapDestructorHelper(bool clearMaps) 2709 { 2710 HeapStats initialHeapStats; 2711 clearOutOldGarbage(&initialHeapStats); 2712 ThingWithDestructor::s_liveThingsWithDestructor = 0; 2713 2714 typedef HeapHashMap<WeakMember<IntWrapper>, RefPtr<RefCountedAndGarbageCollected> > RefMap; 2715 2716 typedef HeapHashMap< 2717 WeakMember<IntWrapper>, 2718 ThingWithDestructor, 2719 DefaultHash<WeakMember<IntWrapper> >::Hash, 2720 HashTraits<WeakMember<IntWrapper> >, 2721 ThingWithDestructorTraits> Map; 2722 2723 Persistent<Map> map(new Map()); 2724 Persistent<RefMap> refMap(new RefMap()); 2725 2726 Persistent<IntWrapper> luck(IntWrapper::create(103)); 2727 2728 int baseLine, refBaseLine; 2729 2730 { 2731 Map stackMap; 2732 RefMap stackRefMap; 2733 2734 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2735 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2736 2737 stackMap.add(IntWrapper::create(42), ThingWithDestructor(1729)); 2738 stackMap.add(luck, ThingWithDestructor(8128)); 2739 stackRefMap.add(IntWrapper::create(42), RefCountedAndGarbageCollected::create()); 2740 stackRefMap.add(luck, RefCountedAndGarbageCollected::create()); 2741 2742 baseLine = ThingWithDestructor::s_liveThingsWithDestructor; 2743 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls; 2744 2745 // Although the heap maps are on-stack, we can't expect prompt 2746 // finalization of the elements, so when they go out of scope here we 2747 // will not necessarily have called the relevant destructors. 2748 } 2749 2750 // The RefCountedAndGarbageCollected things need an extra GC to discover 2751 // that they are no longer ref counted. 2752 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2753 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2754 EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor); 2755 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls); 2756 2757 // Now use maps kept alive with persistents. Here we don't expect any 2758 // destructors to be called before there have been GCs. 2759 2760 map->add(IntWrapper::create(42), ThingWithDestructor(1729)); 2761 map->add(luck, ThingWithDestructor(8128)); 2762 refMap->add(IntWrapper::create(42), RefCountedAndGarbageCollected::create()); 2763 refMap->add(luck, RefCountedAndGarbageCollected::create()); 2764 2765 baseLine = ThingWithDestructor::s_liveThingsWithDestructor; 2766 refBaseLine = RefCountedAndGarbageCollected::s_destructorCalls; 2767 2768 luck.clear(); 2769 if (clearMaps) { 2770 map->clear(); // Clear map. 2771 refMap->clear(); // Clear map. 2772 } else { 2773 map.clear(); // Clear Persistent handle, not map. 2774 refMap.clear(); // Clear Persistent handle, not map. 2775 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2776 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2777 } 2778 2779 EXPECT_EQ(baseLine - 2, ThingWithDestructor::s_liveThingsWithDestructor); 2780 2781 // Need a GC to make sure that the RefCountedAndGarbageCollected thing 2782 // noticies it's been decremented to zero. 2783 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2784 EXPECT_EQ(refBaseLine + 2, RefCountedAndGarbageCollected::s_destructorCalls); 2785 } 2786 2787 TEST(HeapTest, HeapMapDestructor) 2788 { 2789 heapMapDestructorHelper(true); 2790 heapMapDestructorHelper(false); 2791 } 2792 2793 typedef HeapHashSet<PairWeakStrong> WeakStrongSet; 2794 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet; 2795 typedef HeapHashSet<PairStrongWeak> StrongWeakSet; 2796 typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet; 2797 typedef HeapLinkedHashSet<PairWeakStrong> WeakStrongLinkedSet; 2798 typedef HeapLinkedHashSet<PairWeakUnwrapped> WeakUnwrappedLinkedSet; 2799 typedef HeapLinkedHashSet<PairStrongWeak> StrongWeakLinkedSet; 2800 typedef HeapLinkedHashSet<PairUnwrappedWeak> UnwrappedWeakLinkedSet; 2801 typedef HeapHashCountedSet<PairWeakStrong> WeakStrongCountedSet; 2802 typedef HeapHashCountedSet<PairWeakUnwrapped> WeakUnwrappedCountedSet; 2803 typedef HeapHashCountedSet<PairStrongWeak> StrongWeakCountedSet; 2804 typedef HeapHashCountedSet<PairUnwrappedWeak> UnwrappedWeakCountedSet; 2805 2806 template<typename T> 2807 T& iteratorExtractor(WTF::KeyValuePair<T, unsigned>& pair) 2808 { 2809 return pair.key; 2810 } 2811 2812 template<typename T> 2813 T& iteratorExtractor(T& notAPair) 2814 { 2815 return notAPair; 2816 } 2817 2818 template<typename WSSet, typename SWSet, typename WUSet, typename UWSet> 2819 void checkPairSets( 2820 Persistent<WSSet>& weakStrong, 2821 Persistent<SWSet>& strongWeak, 2822 Persistent<WUSet>& weakUnwrapped, 2823 Persistent<UWSet>& unwrappedWeak, 2824 bool ones, 2825 Persistent<IntWrapper>& two) 2826 { 2827 typename WSSet::iterator itWS = weakStrong->begin(); 2828 typename SWSet::iterator itSW = strongWeak->begin(); 2829 typename WUSet::iterator itWU = weakUnwrapped->begin(); 2830 typename UWSet::iterator itUW = unwrappedWeak->begin(); 2831 2832 EXPECT_EQ(2u, weakStrong->size()); 2833 EXPECT_EQ(2u, strongWeak->size()); 2834 EXPECT_EQ(2u, weakUnwrapped->size()); 2835 EXPECT_EQ(2u, unwrappedWeak->size()); 2836 2837 PairWeakStrong p = iteratorExtractor(*itWS); 2838 PairStrongWeak p2 = iteratorExtractor(*itSW); 2839 PairWeakUnwrapped p3 = iteratorExtractor(*itWU); 2840 PairUnwrappedWeak p4 = iteratorExtractor(*itUW); 2841 if (p.first == two && p.second == two) 2842 ++itWS; 2843 if (p2.first == two && p2.second == two) 2844 ++itSW; 2845 if (p3.first == two && p3.second == 2) 2846 ++itWU; 2847 if (p4.first == 2 && p4.second == two) 2848 ++itUW; 2849 p = iteratorExtractor(*itWS); 2850 p2 = iteratorExtractor(*itSW); 2851 p3 = iteratorExtractor(*itWU); 2852 p4 = iteratorExtractor(*itUW); 2853 IntWrapper* nullWrapper = 0; 2854 if (ones) { 2855 EXPECT_EQ(p.first->value(), 1); 2856 EXPECT_EQ(p2.second->value(), 1); 2857 EXPECT_EQ(p3.first->value(), 1); 2858 EXPECT_EQ(p4.second->value(), 1); 2859 } else { 2860 EXPECT_EQ(p.first, nullWrapper); 2861 EXPECT_EQ(p2.second, nullWrapper); 2862 EXPECT_EQ(p3.first, nullWrapper); 2863 EXPECT_EQ(p4.second, nullWrapper); 2864 } 2865 2866 EXPECT_EQ(p.second->value(), 2); 2867 EXPECT_EQ(p2.first->value(), 2); 2868 EXPECT_EQ(p3.second, 2); 2869 EXPECT_EQ(p4.first, 2); 2870 2871 EXPECT_TRUE(weakStrong->contains(PairWeakStrong(&*two, &*two))); 2872 EXPECT_TRUE(strongWeak->contains(PairStrongWeak(&*two, &*two))); 2873 EXPECT_TRUE(weakUnwrapped->contains(PairWeakUnwrapped(&*two, 2))); 2874 EXPECT_TRUE(unwrappedWeak->contains(PairUnwrappedWeak(2, &*two))); 2875 } 2876 2877 template<typename WSSet, typename SWSet, typename WUSet, typename UWSet> 2878 void weakPairsHelper() 2879 { 2880 IntWrapper::s_destructorCalls = 0; 2881 2882 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive; 2883 2884 Persistent<WSSet> weakStrong = new WSSet(); 2885 Persistent<SWSet> strongWeak = new SWSet(); 2886 Persistent<WUSet> weakUnwrapped = new WUSet(); 2887 Persistent<UWSet> unwrappedWeak = new UWSet(); 2888 2889 Persistent<IntWrapper> two = IntWrapper::create(2); 2890 2891 weakStrong->add(PairWeakStrong(IntWrapper::create(1), &*two)); 2892 weakStrong->add(PairWeakStrong(&*two, &*two)); 2893 strongWeak->add(PairStrongWeak(&*two, IntWrapper::create(1))); 2894 strongWeak->add(PairStrongWeak(&*two, &*two)); 2895 weakUnwrapped->add(PairWeakUnwrapped(IntWrapper::create(1), 2)); 2896 weakUnwrapped->add(PairWeakUnwrapped(&*two, 2)); 2897 unwrappedWeak->add(PairUnwrappedWeak(2, IntWrapper::create(1))); 2898 unwrappedWeak->add(PairUnwrappedWeak(2, &*two)); 2899 2900 checkPairSets<WSSet, SWSet, WUSet, UWSet>(weakStrong, strongWeak, weakUnwrapped, unwrappedWeak, true, two); 2901 2902 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2903 checkPairSets<WSSet, SWSet, WUSet, UWSet>(weakStrong, strongWeak, weakUnwrapped, unwrappedWeak, false, two); 2904 } 2905 2906 TEST(HeapTest, HeapWeakPairs) 2907 { 2908 { 2909 typedef HeapHashSet<PairWeakStrong> WeakStrongSet; 2910 typedef HeapHashSet<PairWeakUnwrapped> WeakUnwrappedSet; 2911 typedef HeapHashSet<PairStrongWeak> StrongWeakSet; 2912 typedef HeapHashSet<PairUnwrappedWeak> UnwrappedWeakSet; 2913 weakPairsHelper<WeakStrongSet, StrongWeakSet, WeakUnwrappedSet, UnwrappedWeakSet>(); 2914 } 2915 2916 { 2917 typedef HeapListHashSet<PairWeakStrong> WeakStrongSet; 2918 typedef HeapListHashSet<PairWeakUnwrapped> WeakUnwrappedSet; 2919 typedef HeapListHashSet<PairStrongWeak> StrongWeakSet; 2920 typedef HeapListHashSet<PairUnwrappedWeak> UnwrappedWeakSet; 2921 weakPairsHelper<WeakStrongSet, StrongWeakSet, WeakUnwrappedSet, UnwrappedWeakSet>(); 2922 } 2923 2924 { 2925 typedef HeapLinkedHashSet<PairWeakStrong> WeakStrongSet; 2926 typedef HeapLinkedHashSet<PairWeakUnwrapped> WeakUnwrappedSet; 2927 typedef HeapLinkedHashSet<PairStrongWeak> StrongWeakSet; 2928 typedef HeapLinkedHashSet<PairUnwrappedWeak> UnwrappedWeakSet; 2929 weakPairsHelper<WeakStrongSet, StrongWeakSet, WeakUnwrappedSet, UnwrappedWeakSet>(); 2930 } 2931 } 2932 2933 TEST(HeapTest, HeapWeakCollectionTypes) 2934 { 2935 HeapStats initialHeapSize; 2936 IntWrapper::s_destructorCalls = 0; 2937 2938 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakStrong; 2939 typedef HeapHashMap<Member<IntWrapper>, WeakMember<IntWrapper> > StrongWeak; 2940 typedef HeapHashMap<WeakMember<IntWrapper>, WeakMember<IntWrapper> > WeakWeak; 2941 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet; 2942 typedef HeapLinkedHashSet<WeakMember<IntWrapper> > WeakOrderedSet; 2943 2944 clearOutOldGarbage(&initialHeapSize); 2945 2946 const int weakStrongIndex = 0; 2947 const int strongWeakIndex = 1; 2948 const int weakWeakIndex = 2; 2949 const int numberOfMapIndices = 3; 2950 const int weakSetIndex = 3; 2951 const int weakOrderedSetIndex = 4; 2952 const int numberOfCollections = 5; 2953 2954 for (int testRun = 0; testRun < 4; testRun++) { 2955 for (int collectionNumber = 0; collectionNumber < numberOfCollections; collectionNumber++) { 2956 bool deleteAfterwards = (testRun == 1); 2957 bool addAfterwards = (testRun == 2); 2958 bool testThatIteratorsMakeStrong = (testRun == 3); 2959 2960 // The test doesn't work for strongWeak with deleting because we lost 2961 // the key from the keepNumbersAlive array, so we can't do the lookup. 2962 if (deleteAfterwards && collectionNumber == strongWeakIndex) 2963 continue; 2964 2965 unsigned added = addAfterwards ? 100 : 0; 2966 2967 Persistent<WeakStrong> weakStrong = new WeakStrong(); 2968 Persistent<StrongWeak> strongWeak = new StrongWeak(); 2969 Persistent<WeakWeak> weakWeak = new WeakWeak(); 2970 2971 Persistent<WeakSet> weakSet = new WeakSet(); 2972 Persistent<WeakOrderedSet> weakOrderedSet = new WeakOrderedSet(); 2973 2974 PersistentHeapVector<Member<IntWrapper> > keepNumbersAlive; 2975 for (int i = 0; i < 128; i += 2) { 2976 IntWrapper* wrapped = IntWrapper::create(i); 2977 IntWrapper* wrapped2 = IntWrapper::create(i + 1); 2978 keepNumbersAlive.append(wrapped); 2979 keepNumbersAlive.append(wrapped2); 2980 weakStrong->add(wrapped, wrapped2); 2981 strongWeak->add(wrapped2, wrapped); 2982 weakWeak->add(wrapped, wrapped2); 2983 weakSet->add(wrapped); 2984 weakOrderedSet->add(wrapped); 2985 } 2986 2987 EXPECT_EQ(64u, weakStrong->size()); 2988 EXPECT_EQ(64u, strongWeak->size()); 2989 EXPECT_EQ(64u, weakWeak->size()); 2990 EXPECT_EQ(64u, weakSet->size()); 2991 EXPECT_EQ(64u, weakOrderedSet->size()); 2992 2993 // Collect garbage. This should change nothing since we are keeping 2994 // alive the IntWrapper objects. 2995 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 2996 2997 EXPECT_EQ(64u, weakStrong->size()); 2998 EXPECT_EQ(64u, strongWeak->size()); 2999 EXPECT_EQ(64u, weakWeak->size()); 3000 EXPECT_EQ(64u, weakSet->size()); 3001 EXPECT_EQ(64u, weakOrderedSet->size()); 3002 3003 for (int i = 0; i < 128; i += 2) { 3004 IntWrapper* wrapped = keepNumbersAlive[i]; 3005 IntWrapper* wrapped2 = keepNumbersAlive[i + 1]; 3006 EXPECT_EQ(wrapped2, weakStrong->get(wrapped)); 3007 EXPECT_EQ(wrapped, strongWeak->get(wrapped2)); 3008 EXPECT_EQ(wrapped2, weakWeak->get(wrapped)); 3009 EXPECT_TRUE(weakSet->contains(wrapped)); 3010 EXPECT_TRUE(weakOrderedSet->contains(wrapped)); 3011 } 3012 3013 for (int i = 0; i < 128; i += 3) 3014 keepNumbersAlive[i] = nullptr; 3015 3016 if (collectionNumber != weakStrongIndex) 3017 weakStrong->clear(); 3018 if (collectionNumber != strongWeakIndex) 3019 strongWeak->clear(); 3020 if (collectionNumber != weakWeakIndex) 3021 weakWeak->clear(); 3022 if (collectionNumber != weakSetIndex) 3023 weakSet->clear(); 3024 if (collectionNumber != weakOrderedSetIndex) 3025 weakOrderedSet->clear(); 3026 3027 if (testThatIteratorsMakeStrong) { 3028 WeakStrong::iterator it1 = weakStrong->begin(); 3029 StrongWeak::iterator it2 = strongWeak->begin(); 3030 WeakWeak::iterator it3 = weakWeak->begin(); 3031 WeakSet::iterator it4 = weakSet->begin(); 3032 WeakOrderedSet::iterator it5 = weakOrderedSet->begin(); 3033 // Collect garbage. This should change nothing since the 3034 // iterators make the collections strong. 3035 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3036 if (collectionNumber == weakStrongIndex) { 3037 EXPECT_EQ(64u, weakStrong->size()); 3038 MapIteratorCheck(it1, weakStrong->end(), 64); 3039 } else if (collectionNumber == strongWeakIndex) { 3040 EXPECT_EQ(64u, strongWeak->size()); 3041 MapIteratorCheck(it2, strongWeak->end(), 64); 3042 } else if (collectionNumber == weakWeakIndex) { 3043 EXPECT_EQ(64u, weakWeak->size()); 3044 MapIteratorCheck(it3, weakWeak->end(), 64); 3045 } else if (collectionNumber == weakSetIndex) { 3046 EXPECT_EQ(64u, weakSet->size()); 3047 SetIteratorCheck(it4, weakSet->end(), 64); 3048 } else if (collectionNumber == weakOrderedSetIndex) { 3049 EXPECT_EQ(64u, weakOrderedSet->size()); 3050 SetIteratorCheck(it5, weakOrderedSet->end(), 64); 3051 } 3052 } else { 3053 // Collect garbage. This causes weak processing to remove 3054 // things from the collections. 3055 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3056 unsigned count = 0; 3057 for (int i = 0; i < 128; i += 2) { 3058 bool firstAlive = keepNumbersAlive[i]; 3059 bool secondAlive = keepNumbersAlive[i + 1]; 3060 if (firstAlive && (collectionNumber == weakStrongIndex || collectionNumber == strongWeakIndex)) 3061 secondAlive = true; 3062 if (firstAlive && secondAlive && collectionNumber < numberOfMapIndices) { 3063 if (collectionNumber == weakStrongIndex) { 3064 if (deleteAfterwards) 3065 EXPECT_EQ(i + 1, weakStrong->take(keepNumbersAlive[i])->value()); 3066 } else if (collectionNumber == strongWeakIndex) { 3067 if (deleteAfterwards) 3068 EXPECT_EQ(i, strongWeak->take(keepNumbersAlive[i + 1])->value()); 3069 } else if (collectionNumber == weakWeakIndex) { 3070 if (deleteAfterwards) 3071 EXPECT_EQ(i + 1, weakWeak->take(keepNumbersAlive[i])->value()); 3072 } 3073 if (!deleteAfterwards) 3074 count++; 3075 } else if (collectionNumber == weakSetIndex && firstAlive) { 3076 ASSERT_TRUE(weakSet->contains(keepNumbersAlive[i])); 3077 if (deleteAfterwards) 3078 weakSet->remove(keepNumbersAlive[i]); 3079 else 3080 count++; 3081 } else if (collectionNumber == weakOrderedSetIndex && firstAlive) { 3082 ASSERT_TRUE(weakOrderedSet->contains(keepNumbersAlive[i])); 3083 if (deleteAfterwards) 3084 weakOrderedSet->remove(keepNumbersAlive[i]); 3085 else 3086 count++; 3087 } 3088 } 3089 if (addAfterwards) { 3090 for (int i = 1000; i < 1100; i++) { 3091 IntWrapper* wrapped = IntWrapper::create(i); 3092 keepNumbersAlive.append(wrapped); 3093 weakStrong->add(wrapped, wrapped); 3094 strongWeak->add(wrapped, wrapped); 3095 weakWeak->add(wrapped, wrapped); 3096 weakSet->add(wrapped); 3097 weakOrderedSet->add(wrapped); 3098 } 3099 } 3100 if (collectionNumber == weakStrongIndex) 3101 EXPECT_EQ(count + added, weakStrong->size()); 3102 else if (collectionNumber == strongWeakIndex) 3103 EXPECT_EQ(count + added, strongWeak->size()); 3104 else if (collectionNumber == weakWeakIndex) 3105 EXPECT_EQ(count + added, weakWeak->size()); 3106 else if (collectionNumber == weakSetIndex) 3107 EXPECT_EQ(count + added, weakSet->size()); 3108 else if (collectionNumber == weakOrderedSetIndex) 3109 EXPECT_EQ(count + added, weakOrderedSet->size()); 3110 WeakStrong::iterator it1 = weakStrong->begin(); 3111 StrongWeak::iterator it2 = strongWeak->begin(); 3112 WeakWeak::iterator it3 = weakWeak->begin(); 3113 WeakSet::iterator it4 = weakSet->begin(); 3114 WeakOrderedSet::iterator it5 = weakOrderedSet->begin(); 3115 MapIteratorCheck(it1, weakStrong->end(), (collectionNumber == weakStrongIndex ? count : 0) + added); 3116 MapIteratorCheck(it2, strongWeak->end(), (collectionNumber == strongWeakIndex ? count : 0) + added); 3117 MapIteratorCheck(it3, weakWeak->end(), (collectionNumber == weakWeakIndex ? count : 0) + added); 3118 SetIteratorCheck(it4, weakSet->end(), (collectionNumber == weakSetIndex ? count : 0) + added); 3119 SetIteratorCheck(it5, weakOrderedSet->end(), (collectionNumber == weakOrderedSetIndex ? count : 0) + added); 3120 } 3121 for (unsigned i = 0; i < 128 + added; i++) 3122 keepNumbersAlive[i] = nullptr; 3123 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3124 EXPECT_EQ(0u, weakStrong->size()); 3125 EXPECT_EQ(0u, strongWeak->size()); 3126 EXPECT_EQ(0u, weakWeak->size()); 3127 EXPECT_EQ(0u, weakSet->size()); 3128 EXPECT_EQ(0u, weakOrderedSet->size()); 3129 } 3130 } 3131 } 3132 3133 TEST(HeapTest, RefCountedGarbageCollected) 3134 { 3135 RefCountedAndGarbageCollected::s_destructorCalls = 0; 3136 { 3137 RefPtr<RefCountedAndGarbageCollected> refPtr3; 3138 { 3139 Persistent<RefCountedAndGarbageCollected> persistent; 3140 { 3141 RefPtr<RefCountedAndGarbageCollected> refPtr1 = RefCountedAndGarbageCollected::create(); 3142 RefPtr<RefCountedAndGarbageCollected> refPtr2 = RefCountedAndGarbageCollected::create(); 3143 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3144 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls); 3145 persistent = refPtr1.get(); 3146 } 3147 // Reference count is zero for both objects but one of 3148 // them is kept alive by a persistent handle. 3149 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3150 EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls); 3151 refPtr3 = persistent.get(); 3152 } 3153 // The persistent handle is gone but the ref count has been 3154 // increased to 1. 3155 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3156 EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls); 3157 } 3158 // Both persistent handle is gone and ref count is zero so the 3159 // object can be collected. 3160 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3161 EXPECT_EQ(2, RefCountedAndGarbageCollected::s_destructorCalls); 3162 } 3163 3164 TEST(HeapTest, RefCountedGarbageCollectedWithStackPointers) 3165 { 3166 RefCountedAndGarbageCollected::s_destructorCalls = 0; 3167 RefCountedAndGarbageCollected2::s_destructorCalls = 0; 3168 { 3169 RefCountedAndGarbageCollected* pointer1 = 0; 3170 RefCountedAndGarbageCollected2* pointer2 = 0; 3171 { 3172 RefPtr<RefCountedAndGarbageCollected> object1 = RefCountedAndGarbageCollected::create(); 3173 RefPtr<RefCountedAndGarbageCollected2> object2 = RefCountedAndGarbageCollected2::create(); 3174 pointer1 = object1.get(); 3175 pointer2 = object2.get(); 3176 void* objects[2] = { object1.get(), object2.get() }; 3177 RefCountedGarbageCollectedVisitor visitor(2, objects); 3178 ThreadState::current()->visitPersistents(&visitor); 3179 EXPECT_TRUE(visitor.validate()); 3180 3181 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3182 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls); 3183 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls); 3184 } 3185 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3186 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls); 3187 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls); 3188 3189 // At this point, the reference counts of object1 and object2 are 0. 3190 // Only pointer1 and pointer2 keep references to object1 and object2. 3191 void* objects[] = { 0 }; 3192 RefCountedGarbageCollectedVisitor visitor(0, objects); 3193 ThreadState::current()->visitPersistents(&visitor); 3194 EXPECT_TRUE(visitor.validate()); 3195 3196 { 3197 RefPtr<RefCountedAndGarbageCollected> object1(pointer1); 3198 RefPtr<RefCountedAndGarbageCollected2> object2(pointer2); 3199 void* objects[2] = { object1.get(), object2.get() }; 3200 RefCountedGarbageCollectedVisitor visitor(2, objects); 3201 ThreadState::current()->visitPersistents(&visitor); 3202 EXPECT_TRUE(visitor.validate()); 3203 3204 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3205 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls); 3206 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls); 3207 } 3208 3209 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3210 EXPECT_EQ(0, RefCountedAndGarbageCollected::s_destructorCalls); 3211 EXPECT_EQ(0, RefCountedAndGarbageCollected2::s_destructorCalls); 3212 } 3213 3214 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3215 EXPECT_EQ(1, RefCountedAndGarbageCollected::s_destructorCalls); 3216 EXPECT_EQ(1, RefCountedAndGarbageCollected2::s_destructorCalls); 3217 } 3218 3219 TEST(HeapTest, WeakMembers) 3220 { 3221 Bar::s_live = 0; 3222 { 3223 Persistent<Bar> h1 = Bar::create(); 3224 Persistent<Weak> h4; 3225 Persistent<WithWeakMember> h5; 3226 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3227 ASSERT_EQ(1u, Bar::s_live); // h1 is live. 3228 { 3229 Bar* h2 = Bar::create(); 3230 Bar* h3 = Bar::create(); 3231 h4 = Weak::create(h2, h3); 3232 h5 = WithWeakMember::create(h2, h3); 3233 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3234 EXPECT_EQ(5u, Bar::s_live); // The on-stack pointer keeps h3 alive. 3235 EXPECT_TRUE(h4->strongIsThere()); 3236 EXPECT_TRUE(h4->weakIsThere()); 3237 EXPECT_TRUE(h5->strongIsThere()); 3238 EXPECT_TRUE(h5->weakIsThere()); 3239 } 3240 // h3 is collected, weak pointers from h4 and h5 don't keep it alive. 3241 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3242 EXPECT_EQ(4u, Bar::s_live); 3243 EXPECT_TRUE(h4->strongIsThere()); 3244 EXPECT_FALSE(h4->weakIsThere()); // h3 is gone from weak pointer. 3245 EXPECT_TRUE(h5->strongIsThere()); 3246 EXPECT_FALSE(h5->weakIsThere()); // h3 is gone from weak pointer. 3247 h1.release(); // Zero out h1. 3248 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3249 EXPECT_EQ(3u, Bar::s_live); // Only h4, h5 and h2 are left. 3250 EXPECT_TRUE(h4->strongIsThere()); // h2 is still pointed to from h4. 3251 EXPECT_TRUE(h5->strongIsThere()); // h2 is still pointed to from h5. 3252 } 3253 // h4 and h5 have gone out of scope now and they were keeping h2 alive. 3254 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3255 EXPECT_EQ(0u, Bar::s_live); // All gone. 3256 } 3257 3258 TEST(HeapTest, FinalizationObserver) 3259 { 3260 Persistent<FinalizationObserver<Observable> > o; 3261 { 3262 Observable* foo = Observable::create(Bar::create()); 3263 // |o| observes |foo|. 3264 o = FinalizationObserver<Observable>::create(foo); 3265 } 3266 // FinalizationObserver doesn't have a strong reference to |foo|. So |foo| 3267 // and its member will be collected. 3268 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3269 EXPECT_EQ(0u, Bar::s_live); 3270 EXPECT_TRUE(o->didCallWillFinalize()); 3271 3272 FinalizationObserverWithHashMap::s_didCallWillFinalize = false; 3273 Observable* foo = Observable::create(Bar::create()); 3274 FinalizationObserverWithHashMap::ObserverMap& map = FinalizationObserverWithHashMap::observe(*foo); 3275 EXPECT_EQ(1u, map.size()); 3276 foo = 0; 3277 // FinalizationObserverWithHashMap doesn't have a strong reference to 3278 // |foo|. So |foo| and its member will be collected. 3279 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3280 EXPECT_EQ(0u, Bar::s_live); 3281 EXPECT_EQ(0u, map.size()); 3282 EXPECT_TRUE(FinalizationObserverWithHashMap::s_didCallWillFinalize); 3283 } 3284 3285 TEST(HeapTest, Comparisons) 3286 { 3287 Persistent<Bar> barPersistent = Bar::create(); 3288 Persistent<Foo> fooPersistent = Foo::create(barPersistent); 3289 EXPECT_TRUE(barPersistent != fooPersistent); 3290 barPersistent = fooPersistent; 3291 EXPECT_TRUE(barPersistent == fooPersistent); 3292 } 3293 3294 TEST(HeapTest, CheckAndMarkPointer) 3295 { 3296 HeapStats initialHeapStats; 3297 clearOutOldGarbage(&initialHeapStats); 3298 3299 Vector<Address> objectAddresses; 3300 Vector<Address> endAddresses; 3301 Address largeObjectAddress; 3302 Address largeObjectEndAddress; 3303 CountingVisitor visitor; 3304 for (int i = 0; i < 10; i++) { 3305 SimpleObject* object = SimpleObject::create(); 3306 Address objectAddress = reinterpret_cast<Address>(object); 3307 objectAddresses.append(objectAddress); 3308 endAddresses.append(objectAddress + sizeof(SimpleObject) - 1); 3309 } 3310 LargeObject* largeObject = LargeObject::create(); 3311 largeObjectAddress = reinterpret_cast<Address>(largeObject); 3312 largeObjectEndAddress = largeObjectAddress + sizeof(LargeObject) - 1; 3313 3314 // This is a low-level test where we call checkAndMarkPointer. This method 3315 // causes the object start bitmap to be computed which requires the heap 3316 // to be in a consistent state (e.g. the free allocation area must be put 3317 // into a free list header). However when we call makeConsistentForSweeping it 3318 // also clears out the freelists so we have to rebuild those before trying 3319 // to allocate anything again. We do this by forcing a GC after doing the 3320 // checkAndMarkPointer tests. 3321 { 3322 TestGCScope scope(ThreadState::HeapPointersOnStack); 3323 EXPECT_TRUE(scope.allThreadsParked()); // Fail the test if we could not park all threads. 3324 Heap::makeConsistentForSweeping(); 3325 for (size_t i = 0; i < objectAddresses.size(); i++) { 3326 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, objectAddresses[i])); 3327 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, endAddresses[i])); 3328 } 3329 EXPECT_EQ(objectAddresses.size() * 2, visitor.count()); 3330 visitor.reset(); 3331 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectAddress)); 3332 EXPECT_TRUE(Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress)); 3333 EXPECT_EQ(2ul, visitor.count()); 3334 visitor.reset(); 3335 } 3336 // This forces a GC without stack scanning which results in the objects 3337 // being collected. This will also rebuild the above mentioned freelists, 3338 // however we don't rely on that below since we don't have any allocations. 3339 clearOutOldGarbage(&initialHeapStats); 3340 { 3341 TestGCScope scope(ThreadState::HeapPointersOnStack); 3342 EXPECT_TRUE(scope.allThreadsParked()); 3343 Heap::makeConsistentForSweeping(); 3344 for (size_t i = 0; i < objectAddresses.size(); i++) { 3345 // We would like to assert that checkAndMarkPointer returned false 3346 // here because the pointers no longer point into a valid object 3347 // (it's been freed by the GCs. But checkAndMarkPointer will return 3348 // true for any pointer that points into a heap page, regardless of 3349 // whether it points at a valid object (this ensures the 3350 // correctness of the page-based on-heap address caches), so we 3351 // can't make that assert. 3352 Heap::checkAndMarkPointer(&visitor, objectAddresses[i]); 3353 Heap::checkAndMarkPointer(&visitor, endAddresses[i]); 3354 } 3355 EXPECT_EQ(0ul, visitor.count()); 3356 Heap::checkAndMarkPointer(&visitor, largeObjectAddress); 3357 Heap::checkAndMarkPointer(&visitor, largeObjectEndAddress); 3358 EXPECT_EQ(0ul, visitor.count()); 3359 } 3360 // This round of GC is important to make sure that the object start 3361 // bitmap are cleared out and that the free lists are rebuild. 3362 clearOutOldGarbage(&initialHeapStats); 3363 } 3364 3365 TEST(HeapTest, VisitOffHeapCollections) 3366 { 3367 HeapStats initialHeapStats; 3368 clearOutOldGarbage(&initialHeapStats); 3369 IntWrapper::s_destructorCalls = 0; 3370 Persistent<OffHeapContainer> container = OffHeapContainer::create(); 3371 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3372 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3373 container = nullptr; 3374 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3375 EXPECT_EQ(OffHeapContainer::deadWrappers, IntWrapper::s_destructorCalls); 3376 } 3377 3378 TEST(HeapTest, PersistentHeapCollectionTypes) 3379 { 3380 HeapStats initialHeapSize; 3381 IntWrapper::s_destructorCalls = 0; 3382 3383 typedef HeapVector<Member<IntWrapper> > Vec; 3384 typedef PersistentHeapVector<Member<IntWrapper> > PVec; 3385 typedef PersistentHeapHashSet<Member<IntWrapper> > PSet; 3386 typedef PersistentHeapListHashSet<Member<IntWrapper> > PListSet; 3387 typedef PersistentHeapLinkedHashSet<Member<IntWrapper> > PLinkedSet; 3388 typedef PersistentHeapHashMap<Member<IntWrapper>, Member<IntWrapper> > PMap; 3389 typedef PersistentHeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > WeakPMap; 3390 typedef PersistentHeapDeque<Member<IntWrapper> > PDeque; 3391 3392 clearOutOldGarbage(&initialHeapSize); 3393 { 3394 PVec pVec; 3395 PDeque pDeque; 3396 PSet pSet; 3397 PListSet pListSet; 3398 PLinkedSet pLinkedSet; 3399 PMap pMap; 3400 WeakPMap wpMap; 3401 3402 IntWrapper* one(IntWrapper::create(1)); 3403 IntWrapper* two(IntWrapper::create(2)); 3404 IntWrapper* three(IntWrapper::create(3)); 3405 IntWrapper* four(IntWrapper::create(4)); 3406 IntWrapper* five(IntWrapper::create(5)); 3407 IntWrapper* six(IntWrapper::create(6)); 3408 IntWrapper* seven(IntWrapper::create(7)); 3409 IntWrapper* eight(IntWrapper::create(8)); 3410 IntWrapper* nine(IntWrapper::create(9)); 3411 Persistent<IntWrapper> ten(IntWrapper::create(10)); 3412 IntWrapper* eleven(IntWrapper::create(11)); 3413 3414 pVec.append(one); 3415 pVec.append(two); 3416 3417 pDeque.append(seven); 3418 pDeque.append(two); 3419 3420 Vec* vec = new Vec(); 3421 vec->swap(pVec); 3422 3423 pVec.append(two); 3424 pVec.append(three); 3425 3426 pSet.add(four); 3427 pListSet.add(eight); 3428 pLinkedSet.add(nine); 3429 pMap.add(five, six); 3430 wpMap.add(ten, eleven); 3431 3432 // Collect |vec| and |one|. 3433 vec = 0; 3434 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3435 EXPECT_EQ(1, IntWrapper::s_destructorCalls); 3436 3437 EXPECT_EQ(2u, pVec.size()); 3438 EXPECT_EQ(two, pVec.at(0)); 3439 EXPECT_EQ(three, pVec.at(1)); 3440 3441 EXPECT_EQ(2u, pDeque.size()); 3442 EXPECT_EQ(seven, pDeque.first()); 3443 EXPECT_EQ(seven, pDeque.takeFirst()); 3444 EXPECT_EQ(two, pDeque.first()); 3445 3446 EXPECT_EQ(1u, pDeque.size()); 3447 3448 EXPECT_EQ(1u, pSet.size()); 3449 EXPECT_TRUE(pSet.contains(four)); 3450 3451 EXPECT_EQ(1u, pListSet.size()); 3452 EXPECT_TRUE(pListSet.contains(eight)); 3453 3454 EXPECT_EQ(1u, pLinkedSet.size()); 3455 EXPECT_TRUE(pLinkedSet.contains(nine)); 3456 3457 EXPECT_EQ(1u, pMap.size()); 3458 EXPECT_EQ(six, pMap.get(five)); 3459 3460 EXPECT_EQ(1u, wpMap.size()); 3461 EXPECT_EQ(eleven, wpMap.get(ten)); 3462 ten.clear(); 3463 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3464 EXPECT_EQ(0u, wpMap.size()); 3465 } 3466 3467 // Collect previous roots. 3468 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3469 EXPECT_EQ(11, IntWrapper::s_destructorCalls); 3470 } 3471 3472 TEST(HeapTest, CollectionNesting) 3473 { 3474 HeapStats initialStats; 3475 clearOutOldGarbage(&initialStats); 3476 int* key = &IntWrapper::s_destructorCalls; 3477 IntWrapper::s_destructorCalls = 0; 3478 typedef HeapVector<Member<IntWrapper> > IntVector; 3479 typedef HeapDeque<Member<IntWrapper> > IntDeque; 3480 HeapHashMap<void*, IntVector>* map = new HeapHashMap<void*, IntVector>(); 3481 HeapHashMap<void*, IntDeque>* map2 = new HeapHashMap<void*, IntDeque>(); 3482 3483 map->add(key, IntVector()); 3484 map2->add(key, IntDeque()); 3485 3486 HeapHashMap<void*, IntVector>::iterator it = map->find(key); 3487 EXPECT_EQ(0u, map->get(key).size()); 3488 3489 HeapHashMap<void*, IntDeque>::iterator it2 = map2->find(key); 3490 EXPECT_EQ(0u, map2->get(key).size()); 3491 3492 it->value.append(IntWrapper::create(42)); 3493 EXPECT_EQ(1u, map->get(key).size()); 3494 3495 it2->value.append(IntWrapper::create(42)); 3496 EXPECT_EQ(1u, map2->get(key).size()); 3497 3498 Persistent<HeapHashMap<void*, IntVector> > keepAlive(map); 3499 Persistent<HeapHashMap<void*, IntDeque> > keepAlive2(map2); 3500 3501 for (int i = 0; i < 100; i++) { 3502 map->add(key + 1 + i, IntVector()); 3503 map2->add(key + 1 + i, IntDeque()); 3504 } 3505 3506 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3507 3508 EXPECT_EQ(1u, map->get(key).size()); 3509 EXPECT_EQ(1u, map2->get(key).size()); 3510 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3511 3512 keepAlive = nullptr; 3513 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3514 EXPECT_EQ(1, IntWrapper::s_destructorCalls); 3515 } 3516 3517 TEST(HeapTest, GarbageCollectedMixin) 3518 { 3519 HeapStats initialHeapStats; 3520 clearOutOldGarbage(&initialHeapStats); 3521 3522 Persistent<UseMixin> usemixin = UseMixin::create(); 3523 EXPECT_EQ(0, UseMixin::s_traceCount); 3524 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3525 EXPECT_EQ(1, UseMixin::s_traceCount); 3526 3527 Persistent<Mixin> mixin = usemixin; 3528 usemixin = nullptr; 3529 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3530 EXPECT_EQ(2, UseMixin::s_traceCount); 3531 3532 PersistentHeapHashSet<WeakMember<Mixin> > weakMap; 3533 weakMap.add(UseMixin::create()); 3534 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3535 EXPECT_EQ(0u, weakMap.size()); 3536 } 3537 3538 TEST(HeapTest, CollectionNesting2) 3539 { 3540 HeapStats initialStats; 3541 clearOutOldGarbage(&initialStats); 3542 void* key = &IntWrapper::s_destructorCalls; 3543 IntWrapper::s_destructorCalls = 0; 3544 typedef HeapHashSet<Member<IntWrapper> > IntSet; 3545 HeapHashMap<void*, IntSet>* map = new HeapHashMap<void*, IntSet>(); 3546 3547 map->add(key, IntSet()); 3548 3549 HeapHashMap<void*, IntSet>::iterator it = map->find(key); 3550 EXPECT_EQ(0u, map->get(key).size()); 3551 3552 it->value.add(IntWrapper::create(42)); 3553 EXPECT_EQ(1u, map->get(key).size()); 3554 3555 Persistent<HeapHashMap<void*, IntSet> > keepAlive(map); 3556 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3557 EXPECT_EQ(1u, map->get(key).size()); 3558 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3559 } 3560 3561 TEST(HeapTest, CollectionNesting3) 3562 { 3563 HeapStats initialStats; 3564 clearOutOldGarbage(&initialStats); 3565 IntWrapper::s_destructorCalls = 0; 3566 typedef HeapVector<Member<IntWrapper> > IntVector; 3567 typedef HeapDeque<Member<IntWrapper> > IntDeque; 3568 HeapVector<IntVector>* vector = new HeapVector<IntVector>(); 3569 HeapDeque<IntDeque>* deque = new HeapDeque<IntDeque>(); 3570 3571 vector->append(IntVector()); 3572 deque->append(IntDeque()); 3573 3574 HeapVector<IntVector>::iterator it = vector->begin(); 3575 HeapDeque<IntDeque>::iterator it2 = deque->begin(); 3576 EXPECT_EQ(0u, it->size()); 3577 EXPECT_EQ(0u, it2->size()); 3578 3579 it->append(IntWrapper::create(42)); 3580 it2->append(IntWrapper::create(42)); 3581 EXPECT_EQ(1u, it->size()); 3582 EXPECT_EQ(1u, it2->size()); 3583 3584 Persistent<HeapVector<IntVector> > keepAlive(vector); 3585 Persistent<HeapDeque<IntDeque> > keepAlive2(deque); 3586 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3587 EXPECT_EQ(1u, it->size()); 3588 EXPECT_EQ(1u, it2->size()); 3589 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3590 } 3591 3592 TEST(HeapTest, EmbeddedInVector) 3593 { 3594 HeapStats initialStats; 3595 clearOutOldGarbage(&initialStats); 3596 SimpleFinalizedObject::s_destructorCalls = 0; 3597 { 3598 PersistentHeapVector<VectorObject, 2> inlineVector; 3599 PersistentHeapVector<VectorObject> outlineVector; 3600 VectorObject i1, i2; 3601 inlineVector.append(i1); 3602 inlineVector.append(i2); 3603 3604 VectorObject o1, o2; 3605 outlineVector.append(o1); 3606 outlineVector.append(o2); 3607 3608 PersistentHeapVector<VectorObjectInheritedTrace> vectorInheritedTrace; 3609 VectorObjectInheritedTrace it1, it2; 3610 vectorInheritedTrace.append(it1); 3611 vectorInheritedTrace.append(it2); 3612 3613 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3614 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls); 3615 3616 // Since VectorObjectNoTrace has no trace method it will 3617 // not be traced and hence be collected when doing GC. 3618 // We trace items in a collection braced on the item's 3619 // having a trace method. This is determined via the 3620 // NeedsTracing trait in wtf/TypeTraits.h. 3621 PersistentHeapVector<VectorObjectNoTrace> vectorNoTrace; 3622 VectorObjectNoTrace n1, n2; 3623 vectorNoTrace.append(n1); 3624 vectorNoTrace.append(n2); 3625 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3626 EXPECT_EQ(2, SimpleFinalizedObject::s_destructorCalls); 3627 } 3628 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3629 EXPECT_EQ(8, SimpleFinalizedObject::s_destructorCalls); 3630 } 3631 3632 TEST(HeapTest, EmbeddedInDeque) 3633 { 3634 HeapStats initialStats; 3635 clearOutOldGarbage(&initialStats); 3636 SimpleFinalizedObject::s_destructorCalls = 0; 3637 { 3638 PersistentHeapDeque<VectorObject, 2> inlineDeque; 3639 PersistentHeapDeque<VectorObject> outlineDeque; 3640 VectorObject i1, i2; 3641 inlineDeque.append(i1); 3642 inlineDeque.append(i2); 3643 3644 VectorObject o1, o2; 3645 outlineDeque.append(o1); 3646 outlineDeque.append(o2); 3647 3648 PersistentHeapDeque<VectorObjectInheritedTrace> dequeInheritedTrace; 3649 VectorObjectInheritedTrace it1, it2; 3650 dequeInheritedTrace.append(it1); 3651 dequeInheritedTrace.append(it2); 3652 3653 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3654 EXPECT_EQ(0, SimpleFinalizedObject::s_destructorCalls); 3655 3656 // Since VectorObjectNoTrace has no trace method it will 3657 // not be traced and hence be collected when doing GC. 3658 // We trace items in a collection braced on the item's 3659 // having a trace method. This is determined via the 3660 // NeedsTracing trait in wtf/TypeTraits.h. 3661 PersistentHeapDeque<VectorObjectNoTrace> dequeNoTrace; 3662 VectorObjectNoTrace n1, n2; 3663 dequeNoTrace.append(n1); 3664 dequeNoTrace.append(n2); 3665 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3666 EXPECT_EQ(2, SimpleFinalizedObject::s_destructorCalls); 3667 } 3668 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3669 EXPECT_EQ(8, SimpleFinalizedObject::s_destructorCalls); 3670 } 3671 3672 template<typename Set> 3673 void rawPtrInHashHelper() 3674 { 3675 Set set; 3676 set.add(new int(42)); 3677 set.add(new int(42)); 3678 EXPECT_EQ(2u, set.size()); 3679 for (typename Set::iterator it = set.begin(); it != set.end(); ++it) { 3680 EXPECT_EQ(42, **it); 3681 delete *it; 3682 } 3683 } 3684 3685 TEST(HeapTest, RawPtrInHash) 3686 { 3687 rawPtrInHashHelper<HashSet<RawPtr<int> > >(); 3688 rawPtrInHashHelper<ListHashSet<RawPtr<int> > >(); 3689 rawPtrInHashHelper<LinkedHashSet<RawPtr<int> > >(); 3690 } 3691 3692 TEST(HeapTest, HeapTerminatedArray) 3693 { 3694 HeapStats initialHeapSize; 3695 clearOutOldGarbage(&initialHeapSize); 3696 IntWrapper::s_destructorCalls = 0; 3697 3698 HeapTerminatedArray<TerminatedArrayItem>* arr = 0; 3699 3700 const size_t prefixSize = 4; 3701 const size_t suffixSize = 4; 3702 3703 { 3704 HeapTerminatedArrayBuilder<TerminatedArrayItem> builder(arr); 3705 builder.grow(prefixSize); 3706 for (size_t i = 0; i < prefixSize; i++) 3707 builder.append(TerminatedArrayItem(IntWrapper::create(i))); 3708 arr = builder.release(); 3709 } 3710 3711 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3712 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3713 EXPECT_EQ(prefixSize, arr->size()); 3714 for (size_t i = 0; i < prefixSize; i++) 3715 EXPECT_EQ(i, static_cast<size_t>(arr->at(i).payload()->value())); 3716 3717 { 3718 HeapTerminatedArrayBuilder<TerminatedArrayItem> builder(arr); 3719 builder.grow(suffixSize); 3720 for (size_t i = 0; i < suffixSize; i++) 3721 builder.append(TerminatedArrayItem(IntWrapper::create(prefixSize + i))); 3722 arr = builder.release(); 3723 } 3724 3725 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3726 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3727 EXPECT_EQ(prefixSize + suffixSize, arr->size()); 3728 for (size_t i = 0; i < prefixSize + suffixSize; i++) 3729 EXPECT_EQ(i, static_cast<size_t>(arr->at(i).payload()->value())); 3730 3731 { 3732 Persistent<HeapTerminatedArray<TerminatedArrayItem> > persistentArr = arr; 3733 arr = 0; 3734 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3735 arr = persistentArr.get(); 3736 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3737 EXPECT_EQ(prefixSize + suffixSize, arr->size()); 3738 for (size_t i = 0; i < prefixSize + suffixSize; i++) 3739 EXPECT_EQ(i, static_cast<size_t>(arr->at(i).payload()->value())); 3740 } 3741 3742 arr = 0; 3743 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3744 EXPECT_EQ(8, IntWrapper::s_destructorCalls); 3745 } 3746 3747 TEST(HeapTest, HeapLinkedStack) 3748 { 3749 HeapStats initialHeapSize; 3750 clearOutOldGarbage(&initialHeapSize); 3751 IntWrapper::s_destructorCalls = 0; 3752 3753 HeapLinkedStack<TerminatedArrayItem>* stack = new HeapLinkedStack<TerminatedArrayItem>(); 3754 3755 const size_t stackSize = 10; 3756 3757 for (size_t i = 0; i < stackSize; i++) 3758 stack->push(TerminatedArrayItem(IntWrapper::create(i))); 3759 3760 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3761 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3762 EXPECT_EQ(stackSize, stack->size()); 3763 while (!stack->isEmpty()) { 3764 EXPECT_EQ(stack->size() - 1, static_cast<size_t>(stack->peek().payload()->value())); 3765 stack->pop(); 3766 } 3767 3768 Persistent<HeapLinkedStack<TerminatedArrayItem> > pStack = stack; 3769 3770 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3771 EXPECT_EQ(stackSize, static_cast<size_t>(IntWrapper::s_destructorCalls)); 3772 EXPECT_EQ(0u, pStack->size()); 3773 } 3774 3775 TEST(HeapTest, AllocationDuringFinalization) 3776 { 3777 HeapStats initialHeapSize; 3778 clearOutOldGarbage(&initialHeapSize); 3779 IntWrapper::s_destructorCalls = 0; 3780 OneKiloByteObject::s_destructorCalls = 0; 3781 3782 Persistent<IntWrapper> wrapper; 3783 new FinalizationAllocator(&wrapper); 3784 3785 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3786 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3787 // Check that the wrapper allocated during finalization is not 3788 // swept away and zapped later in the same sweeping phase. 3789 EXPECT_EQ(42, wrapper->value()); 3790 3791 wrapper.clear(); 3792 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3793 EXPECT_EQ(10, IntWrapper::s_destructorCalls); 3794 EXPECT_EQ(512, OneKiloByteObject::s_destructorCalls); 3795 } 3796 3797 class SimpleClassWithDestructor { 3798 public: 3799 SimpleClassWithDestructor() { } 3800 ~SimpleClassWithDestructor() 3801 { 3802 s_wasDestructed = true; 3803 } 3804 static bool s_wasDestructed; 3805 }; 3806 3807 bool SimpleClassWithDestructor::s_wasDestructed; 3808 3809 class RefCountedWithDestructor : public RefCounted<RefCountedWithDestructor> { 3810 public: 3811 RefCountedWithDestructor() { } 3812 ~RefCountedWithDestructor() 3813 { 3814 s_wasDestructed = true; 3815 } 3816 static bool s_wasDestructed; 3817 }; 3818 3819 bool RefCountedWithDestructor::s_wasDestructed; 3820 3821 template<typename Set> 3822 void destructorsCalledOnGC(bool addLots) 3823 { 3824 RefCountedWithDestructor::s_wasDestructed = false; 3825 { 3826 Set set; 3827 RefCountedWithDestructor* hasDestructor = new RefCountedWithDestructor(); 3828 set.add(adoptRef(hasDestructor)); 3829 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed); 3830 3831 if (addLots) { 3832 for (int i = 0; i < 1000; i++) { 3833 set.add(adoptRef(new RefCountedWithDestructor())); 3834 } 3835 } 3836 3837 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed); 3838 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 3839 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed); 3840 } 3841 // The destructors of the sets don't call the destructors of the elements 3842 // in the heap sets. You have to actually remove the elments, call clear() 3843 // or have a GC to get the destructors called. 3844 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed); 3845 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3846 EXPECT_TRUE(RefCountedWithDestructor::s_wasDestructed); 3847 } 3848 3849 template<typename Set> 3850 void destructorsCalledOnClear(bool addLots) 3851 { 3852 RefCountedWithDestructor::s_wasDestructed = false; 3853 Set set; 3854 RefCountedWithDestructor* hasDestructor = new RefCountedWithDestructor(); 3855 set.add(adoptRef(hasDestructor)); 3856 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed); 3857 3858 if (addLots) { 3859 for (int i = 0; i < 1000; i++) { 3860 set.add(adoptRef(new RefCountedWithDestructor())); 3861 } 3862 } 3863 3864 EXPECT_FALSE(RefCountedWithDestructor::s_wasDestructed); 3865 set.clear(); 3866 EXPECT_TRUE(RefCountedWithDestructor::s_wasDestructed); 3867 } 3868 3869 TEST(HeapTest, DestructorsCalled) 3870 { 3871 HeapHashMap<SimpleClassWithDestructor*, OwnPtr<SimpleClassWithDestructor> > map; 3872 SimpleClassWithDestructor* hasDestructor = new SimpleClassWithDestructor(); 3873 map.add(hasDestructor, adoptPtr(hasDestructor)); 3874 SimpleClassWithDestructor::s_wasDestructed = false; 3875 map.clear(); 3876 EXPECT_TRUE(SimpleClassWithDestructor::s_wasDestructed); 3877 3878 destructorsCalledOnClear<HeapHashSet<RefPtr<RefCountedWithDestructor> > >(false); 3879 destructorsCalledOnClear<HeapListHashSet<RefPtr<RefCountedWithDestructor> > >(false); 3880 destructorsCalledOnClear<HeapLinkedHashSet<RefPtr<RefCountedWithDestructor> > >(false); 3881 destructorsCalledOnClear<HeapHashSet<RefPtr<RefCountedWithDestructor> > >(true); 3882 destructorsCalledOnClear<HeapListHashSet<RefPtr<RefCountedWithDestructor> > >(true); 3883 destructorsCalledOnClear<HeapLinkedHashSet<RefPtr<RefCountedWithDestructor> > >(true); 3884 3885 destructorsCalledOnGC<HeapHashSet<RefPtr<RefCountedWithDestructor> > >(false); 3886 destructorsCalledOnGC<HeapListHashSet<RefPtr<RefCountedWithDestructor> > >(false); 3887 destructorsCalledOnGC<HeapLinkedHashSet<RefPtr<RefCountedWithDestructor> > >(false); 3888 destructorsCalledOnGC<HeapHashSet<RefPtr<RefCountedWithDestructor> > >(true); 3889 destructorsCalledOnGC<HeapListHashSet<RefPtr<RefCountedWithDestructor> > >(true); 3890 destructorsCalledOnGC<HeapLinkedHashSet<RefPtr<RefCountedWithDestructor> > >(true); 3891 } 3892 3893 class MixinA : public GarbageCollectedMixin { 3894 public: 3895 MixinA() : m_obj(IntWrapper::create(100)) { } 3896 virtual void trace(Visitor* visitor) 3897 { 3898 visitor->trace(m_obj); 3899 } 3900 Member<IntWrapper> m_obj; 3901 }; 3902 3903 class MixinB : public GarbageCollectedMixin { 3904 public: 3905 MixinB() : m_obj(IntWrapper::create(101)) { } 3906 virtual void trace(Visitor* visitor) 3907 { 3908 visitor->trace(m_obj); 3909 } 3910 Member<IntWrapper> m_obj; 3911 }; 3912 3913 class MultipleMixins : public GarbageCollected<MultipleMixins>, public MixinA, public MixinB { 3914 USING_GARBAGE_COLLECTED_MIXIN(MultipleMixins); 3915 public: 3916 MultipleMixins() : m_obj(IntWrapper::create(102)) { } 3917 virtual void trace(Visitor* visitor) 3918 { 3919 visitor->trace(m_obj); 3920 MixinA::trace(visitor); 3921 MixinB::trace(visitor); 3922 } 3923 Member<IntWrapper> m_obj; 3924 }; 3925 3926 static const bool s_isMixinTrue = IsGarbageCollectedMixin<MultipleMixins>::value; 3927 static const bool s_isMixinFalse = IsGarbageCollectedMixin<IntWrapper>::value; 3928 3929 TEST(HeapTest, MultipleMixins) 3930 { 3931 EXPECT_TRUE(s_isMixinTrue); 3932 EXPECT_FALSE(s_isMixinFalse); 3933 3934 HeapStats initialHeapSize; 3935 clearOutOldGarbage(&initialHeapSize); 3936 IntWrapper::s_destructorCalls = 0; 3937 MultipleMixins* obj = new MultipleMixins(); 3938 { 3939 Persistent<MixinA> a = obj; 3940 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3941 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3942 } 3943 { 3944 Persistent<MixinB> b = obj; 3945 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3946 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 3947 } 3948 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3949 EXPECT_EQ(3, IntWrapper::s_destructorCalls); 3950 } 3951 3952 class GCParkingThreadTester { 3953 public: 3954 static void test() 3955 { 3956 OwnPtr<WebThread> sleepingThread = adoptPtr(Platform::current()->createThread("SleepingThread")); 3957 sleepingThread->postTask(new Task(WTF::bind(sleeperMainFunc))); 3958 3959 // Wait for the sleeper to run. 3960 while (!s_sleeperRunning) { 3961 Platform::current()->yieldCurrentThread(); 3962 } 3963 3964 { 3965 // Expect the first attempt to park the sleeping thread to fail 3966 TestGCScope scope(ThreadState::NoHeapPointersOnStack); 3967 EXPECT_FALSE(scope.allThreadsParked()); 3968 } 3969 3970 s_sleeperDone = true; 3971 3972 // Wait for the sleeper to finish. 3973 while (s_sleeperRunning) { 3974 // We enter the safepoint here since the sleeper thread will detach 3975 // causing it to GC. 3976 ThreadState::current()->safePoint(ThreadState::NoHeapPointersOnStack); 3977 Platform::current()->yieldCurrentThread(); 3978 } 3979 3980 { 3981 // Since the sleeper thread has detached this is the only thread. 3982 TestGCScope scope(ThreadState::NoHeapPointersOnStack); 3983 EXPECT_TRUE(scope.allThreadsParked()); 3984 } 3985 } 3986 3987 private: 3988 static void sleeperMainFunc() 3989 { 3990 ThreadState::attach(); 3991 s_sleeperRunning = true; 3992 3993 // Simulate a long running op that is not entering a safepoint. 3994 while (!s_sleeperDone) { 3995 Platform::current()->yieldCurrentThread(); 3996 } 3997 3998 ThreadState::detach(); 3999 s_sleeperRunning = false; 4000 } 4001 4002 static volatile bool s_sleeperRunning; 4003 static volatile bool s_sleeperDone; 4004 }; 4005 4006 volatile bool GCParkingThreadTester::s_sleeperRunning = false; 4007 volatile bool GCParkingThreadTester::s_sleeperDone = false; 4008 4009 TEST(HeapTest, GCParkingTimeout) 4010 { 4011 GCParkingThreadTester::test(); 4012 } 4013 4014 TEST(HeapTest, NeedsAdjustAndMark) 4015 { 4016 // class Mixin : public GarbageCollectedMixin {}; 4017 EXPECT_TRUE(NeedsAdjustAndMark<Mixin>::value); 4018 EXPECT_TRUE(NeedsAdjustAndMark<const Mixin>::value); 4019 4020 // class SimpleObject : public GarbageCollected<SimpleObject> {}; 4021 EXPECT_FALSE(NeedsAdjustAndMark<SimpleObject>::value); 4022 EXPECT_FALSE(NeedsAdjustAndMark<const SimpleObject>::value); 4023 4024 // class UseMixin : public SimpleObject, public Mixin {}; 4025 EXPECT_FALSE(NeedsAdjustAndMark<UseMixin>::value); 4026 EXPECT_FALSE(NeedsAdjustAndMark<const UseMixin>::value); 4027 } 4028 4029 template<typename Set> 4030 void setWithCustomWeaknessHandling() 4031 { 4032 typedef typename Set::iterator Iterator; 4033 Persistent<IntWrapper> livingInt(IntWrapper::create(42)); 4034 Persistent<Set> set1(new Set()); 4035 { 4036 Set set2; 4037 Set* set3 = new Set(); 4038 set2.add(PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create(1))); 4039 set3->add(PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create(3))); 4040 set1->add(PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create(5))); 4041 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 4042 // The first set is pointed to from a persistent, so it's referenced, but 4043 // the weak processing may have taken place. 4044 if (set1->size()) { 4045 Iterator i1 = set1->begin(); 4046 EXPECT_EQ(4, i1->first->value()); 4047 EXPECT_EQ(5, i1->second->value()); 4048 } 4049 // The second set is on-stack, so its backing store must be referenced from 4050 // the stack. That makes the weak references strong. 4051 Iterator i2 = set2.begin(); 4052 EXPECT_EQ(0, i2->first->value()); 4053 EXPECT_EQ(1, i2->second->value()); 4054 // The third set is pointed to from the stack, so it's referenced, but the 4055 // weak processing may have taken place. 4056 if (set3->size()) { 4057 Iterator i3 = set3->begin(); 4058 EXPECT_EQ(2, i3->first->value()); 4059 EXPECT_EQ(3, i3->second->value()); 4060 } 4061 } 4062 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4063 EXPECT_EQ(0u, set1->size()); 4064 set1->add(PairWithWeakHandling(IntWrapper::create(103), livingInt)); 4065 set1->add(PairWithWeakHandling(livingInt, IntWrapper::create(103))); // This one gets zapped at GC time because nothing holds the 103 alive. 4066 set1->add(PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(103))); // This one gets zapped too. 4067 set1->add(PairWithWeakHandling(livingInt, livingInt)); 4068 set1->add(PairWithWeakHandling(livingInt, livingInt)); // This one is identical to the previous and doesn't add anything. 4069 EXPECT_EQ(4u, set1->size()); 4070 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4071 EXPECT_EQ(2u, set1->size()); 4072 Iterator i1 = set1->begin(); 4073 EXPECT_TRUE(i1->first->value() == 103 || i1->first == livingInt); 4074 EXPECT_EQ(livingInt, i1->second); 4075 ++i1; 4076 EXPECT_TRUE(i1->first->value() == 103 || i1->first == livingInt); 4077 EXPECT_EQ(livingInt, i1->second); 4078 } 4079 4080 TEST(HeapTest, SetWithCustomWeaknessHandling) 4081 { 4082 setWithCustomWeaknessHandling<HeapHashSet<PairWithWeakHandling> >(); 4083 setWithCustomWeaknessHandling<HeapLinkedHashSet<PairWithWeakHandling> >(); 4084 } 4085 4086 TEST(HeapTest, MapWithCustomWeaknessHandling) 4087 { 4088 typedef HeapHashMap<PairWithWeakHandling, RefPtr<OffHeapInt> > Map; 4089 typedef Map::iterator Iterator; 4090 HeapStats initialHeapSize; 4091 clearOutOldGarbage(&initialHeapSize); 4092 OffHeapInt::s_destructorCalls = 0; 4093 4094 Persistent<Map> map1(new Map()); 4095 Persistent<IntWrapper> livingInt(IntWrapper::create(42)); 4096 { 4097 Map map2; 4098 Map* map3 = new Map(); 4099 map2.add(PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create(1)), OffHeapInt::create(1001)); 4100 map3->add(PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create(3)), OffHeapInt::create(1002)); 4101 map1->add(PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create(5)), OffHeapInt::create(1003)); 4102 EXPECT_EQ(0, OffHeapInt::s_destructorCalls); 4103 4104 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 4105 // The first map2 is pointed to from a persistent, so it's referenced, but 4106 // the weak processing may have taken place. 4107 if (map1->size()) { 4108 Iterator i1 = map1->begin(); 4109 EXPECT_EQ(4, i1->key.first->value()); 4110 EXPECT_EQ(5, i1->key.second->value()); 4111 EXPECT_EQ(1003, i1->value->value()); 4112 } 4113 // The second map2 is on-stack, so its backing store must be referenced from 4114 // the stack. That makes the weak references strong. 4115 Iterator i2 = map2.begin(); 4116 EXPECT_EQ(0, i2->key.first->value()); 4117 EXPECT_EQ(1, i2->key.second->value()); 4118 EXPECT_EQ(1001, i2->value->value()); 4119 // The third map2 is pointed to from the stack, so it's referenced, but the 4120 // weak processing may have taken place. 4121 if (map3->size()) { 4122 Iterator i3 = map3->begin(); 4123 EXPECT_EQ(2, i3->key.first->value()); 4124 EXPECT_EQ(3, i3->key.second->value()); 4125 EXPECT_EQ(1002, i3->value->value()); 4126 } 4127 } 4128 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4129 4130 EXPECT_EQ(0u, map1->size()); 4131 EXPECT_EQ(3, OffHeapInt::s_destructorCalls); 4132 4133 OffHeapInt::s_destructorCalls = 0; 4134 4135 map1->add(PairWithWeakHandling(IntWrapper::create(103), livingInt), OffHeapInt::create(2000)); 4136 map1->add(PairWithWeakHandling(livingInt, IntWrapper::create(103)), OffHeapInt::create(2001)); // This one gets zapped at GC time because nothing holds the 103 alive. 4137 map1->add(PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(103)), OffHeapInt::create(2002)); // This one gets zapped too. 4138 RefPtr<OffHeapInt> dupeInt(OffHeapInt::create(2003)); 4139 map1->add(PairWithWeakHandling(livingInt, livingInt), dupeInt); 4140 map1->add(PairWithWeakHandling(livingInt, livingInt), dupeInt); // This one is identical to the previous and doesn't add anything. 4141 dupeInt.clear(); 4142 4143 EXPECT_EQ(0, OffHeapInt::s_destructorCalls); 4144 EXPECT_EQ(4u, map1->size()); 4145 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4146 EXPECT_EQ(2, OffHeapInt::s_destructorCalls); 4147 EXPECT_EQ(2u, map1->size()); 4148 Iterator i1 = map1->begin(); 4149 EXPECT_TRUE(i1->key.first->value() == 103 || i1->key.first == livingInt); 4150 EXPECT_EQ(livingInt, i1->key.second); 4151 ++i1; 4152 EXPECT_TRUE(i1->key.first->value() == 103 || i1->key.first == livingInt); 4153 EXPECT_EQ(livingInt, i1->key.second); 4154 } 4155 4156 TEST(HeapTest, MapWithCustomWeaknessHandling2) 4157 { 4158 typedef HeapHashMap<RefPtr<OffHeapInt>, PairWithWeakHandling> Map; 4159 typedef Map::iterator Iterator; 4160 HeapStats initialHeapSize; 4161 clearOutOldGarbage(&initialHeapSize); 4162 OffHeapInt::s_destructorCalls = 0; 4163 4164 Persistent<Map> map1(new Map()); 4165 Persistent<IntWrapper> livingInt(IntWrapper::create(42)); 4166 4167 { 4168 Map map2; 4169 Map* map3 = new Map(); 4170 map2.add(OffHeapInt::create(1001), PairWithWeakHandling(IntWrapper::create(0), IntWrapper::create(1))); 4171 map3->add(OffHeapInt::create(1002), PairWithWeakHandling(IntWrapper::create(2), IntWrapper::create(3))); 4172 map1->add(OffHeapInt::create(1003), PairWithWeakHandling(IntWrapper::create(4), IntWrapper::create(5))); 4173 EXPECT_EQ(0, OffHeapInt::s_destructorCalls); 4174 4175 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 4176 // The first map2 is pointed to from a persistent, so it's referenced, but 4177 // the weak processing may have taken place. 4178 if (map1->size()) { 4179 Iterator i1 = map1->begin(); 4180 EXPECT_EQ(4, i1->value.first->value()); 4181 EXPECT_EQ(5, i1->value.second->value()); 4182 EXPECT_EQ(1003, i1->key->value()); 4183 } 4184 // The second map2 is on-stack, so its backing store must be referenced from 4185 // the stack. That makes the weak references strong. 4186 Iterator i2 = map2.begin(); 4187 EXPECT_EQ(0, i2->value.first->value()); 4188 EXPECT_EQ(1, i2->value.second->value()); 4189 EXPECT_EQ(1001, i2->key->value()); 4190 // The third map2 is pointed to from the stack, so it's referenced, but the 4191 // weak processing may have taken place. 4192 if (map3->size()) { 4193 Iterator i3 = map3->begin(); 4194 EXPECT_EQ(2, i3->value.first->value()); 4195 EXPECT_EQ(3, i3->value.second->value()); 4196 EXPECT_EQ(1002, i3->key->value()); 4197 } 4198 } 4199 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4200 4201 EXPECT_EQ(0u, map1->size()); 4202 EXPECT_EQ(3, OffHeapInt::s_destructorCalls); 4203 4204 OffHeapInt::s_destructorCalls = 0; 4205 4206 map1->add(OffHeapInt::create(2000), PairWithWeakHandling(IntWrapper::create(103), livingInt)); 4207 map1->add(OffHeapInt::create(2001), PairWithWeakHandling(livingInt, IntWrapper::create(103))); // This one gets zapped at GC time because nothing holds the 103 alive. 4208 map1->add(OffHeapInt::create(2002), PairWithWeakHandling(IntWrapper::create(103), IntWrapper::create(103))); // This one gets zapped too. 4209 RefPtr<OffHeapInt> dupeInt(OffHeapInt::create(2003)); 4210 map1->add(dupeInt, PairWithWeakHandling(livingInt, livingInt)); 4211 map1->add(dupeInt, PairWithWeakHandling(livingInt, livingInt)); // This one is identical to the previous and doesn't add anything. 4212 dupeInt.clear(); 4213 4214 EXPECT_EQ(0, OffHeapInt::s_destructorCalls); 4215 EXPECT_EQ(4u, map1->size()); 4216 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4217 EXPECT_EQ(2, OffHeapInt::s_destructorCalls); 4218 EXPECT_EQ(2u, map1->size()); 4219 Iterator i1 = map1->begin(); 4220 EXPECT_TRUE(i1->value.first->value() == 103 || i1->value.first == livingInt); 4221 EXPECT_EQ(livingInt, i1->value.second); 4222 ++i1; 4223 EXPECT_TRUE(i1->value.first->value() == 103 || i1->value.first == livingInt); 4224 EXPECT_EQ(livingInt, i1->value.second); 4225 } 4226 4227 static void addElementsToWeakMap(HeapHashMap<int, WeakMember<IntWrapper> >* map) 4228 { 4229 // Key cannot be zero in hashmap. 4230 for (int i = 1; i < 11; i++) 4231 map->add(i, IntWrapper::create(i)); 4232 } 4233 4234 // crbug.com/402426 4235 // If it doesn't assert a concurrent modification to the map, then it's passing. 4236 TEST(HeapTest, RegressNullIsStrongified) 4237 { 4238 Persistent<HeapHashMap<int, WeakMember<IntWrapper> > > map = new HeapHashMap<int, WeakMember<IntWrapper> >(); 4239 addElementsToWeakMap(map); 4240 HeapHashMap<int, WeakMember<IntWrapper> >::AddResult result = map->add(800, nullptr); 4241 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 4242 result.storedValue->value = IntWrapper::create(42); 4243 } 4244 4245 TEST(HeapTest, Bind) 4246 { 4247 Closure closure = bind(&Bar::trace, Bar::create(), static_cast<Visitor*>(0)); 4248 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4249 // The closure should have a persistent handle to the Bar. 4250 EXPECT_EQ(1u, Bar::s_live); 4251 4252 Closure closure2 = bind(&Bar::trace, RawPtr<Bar>(Bar::create()), static_cast<Visitor*>(0)); 4253 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4254 // The closure should have a persistent handle to the Bar. 4255 EXPECT_EQ(2u, Bar::s_live); 4256 // RawPtr<OffHeapInt> should not make Persistent. 4257 Closure closure3 = bind(&OffHeapInt::voidFunction, RawPtr<OffHeapInt>(OffHeapInt::create(1).get())); 4258 4259 UseMixin::s_traceCount = 0; 4260 Mixin* mixin = UseMixin::create(); 4261 Closure mixinClosure = bind(&Mixin::trace, mixin, static_cast<Visitor*>(0)); 4262 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4263 // The closure should have a persistent handle to the mixin. 4264 EXPECT_EQ(1, UseMixin::s_traceCount); 4265 } 4266 4267 typedef HeapHashSet<WeakMember<IntWrapper> > WeakSet; 4268 4269 // These special traits will remove a set from a map when the set is empty. 4270 struct EmptyClearingHashSetTraits : HashTraits<WeakSet> { 4271 static const WTF::WeakHandlingFlag weakHandlingFlag = WTF::WeakHandlingInCollections; 4272 static bool traceInCollection(Visitor* visitor, WeakSet& set, WTF::ShouldWeakPointersBeMarkedStrongly strongify) 4273 { 4274 bool liveEntriesFound = false; 4275 WeakSet::iterator end = set.end(); 4276 for (WeakSet::iterator it = set.begin(); it != end; ++it) { 4277 if (visitor->isAlive(*it)) { 4278 liveEntriesFound = true; 4279 break; 4280 } 4281 } 4282 // If there are live entries in the set then the set cannot be removed 4283 // from the map it is contained in, and we need to mark it (and its 4284 // backing) live. We just trace normally, which will invoke the normal 4285 // weak handling for any entries that are not live. 4286 if (liveEntriesFound) 4287 set.trace(visitor); 4288 return !liveEntriesFound; 4289 } 4290 }; 4291 4292 // This is an example to show how you can remove entries from a T->WeakSet map 4293 // when the weak sets become empty. For this example we are using a type that 4294 // is given to use (HeapHashSet) rather than a type of our own. This means: 4295 // 1) We can't just override the HashTrait for the type since this would affect 4296 // all collections that use this kind of weak set. Instead we have our own 4297 // traits and use a map with custom traits for the value type. These traits 4298 // are the 5th template parameter, so we have to supply default values for 4299 // the 3rd and 4th template parameters 4300 // 2) We can't just inherit from WeakHandlingHashTraits, since that trait 4301 // assumes we can add methods to the type, but we can't add methods to 4302 // HeapHashSet. 4303 TEST(HeapTest, RemoveEmptySets) 4304 { 4305 HeapStats initialHeapSize; 4306 clearOutOldGarbage(&initialHeapSize); 4307 OffHeapInt::s_destructorCalls = 0; 4308 4309 Persistent<IntWrapper> livingInt(IntWrapper::create(42)); 4310 4311 typedef RefPtr<OffHeapInt> Key; 4312 typedef HeapHashMap<Key, WeakSet, WTF::DefaultHash<Key>::Hash, HashTraits<Key>, EmptyClearingHashSetTraits> Map; 4313 Persistent<Map> map(new Map()); 4314 map->add(OffHeapInt::create(1), WeakSet()); 4315 { 4316 WeakSet& set = map->begin()->value; 4317 set.add(IntWrapper::create(103)); // Weak set can't hold this long. 4318 set.add(livingInt); // This prevents the set from being emptied. 4319 EXPECT_EQ(2u, set.size()); 4320 } 4321 4322 // The set we add here is empty, so the entry will be removed from the map 4323 // at the next GC. 4324 map->add(OffHeapInt::create(2), WeakSet()); 4325 EXPECT_EQ(2u, map->size()); 4326 4327 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4328 EXPECT_EQ(1u, map->size()); // The one with key 2 was removed. 4329 EXPECT_EQ(1, OffHeapInt::s_destructorCalls); 4330 { 4331 WeakSet& set = map->begin()->value; 4332 EXPECT_EQ(1u, set.size()); 4333 } 4334 4335 livingInt.clear(); // The weak set can no longer keep the '42' alive now. 4336 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4337 EXPECT_EQ(0u, map->size()); 4338 } 4339 4340 TEST(HeapTest, EphemeronsInEphemerons) 4341 { 4342 typedef HeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > InnerMap; 4343 typedef HeapHashMap<WeakMember<IntWrapper>, InnerMap> OuterMap; 4344 4345 for (int keepOuterAlive = 0; keepOuterAlive <= 1; keepOuterAlive++) { 4346 for (int keepInnerAlive = 0; keepInnerAlive <=1; keepInnerAlive++) { 4347 Persistent<OuterMap> outer = new OuterMap(); 4348 Persistent<IntWrapper> one = IntWrapper::create(1); 4349 Persistent<IntWrapper> two = IntWrapper::create(2); 4350 outer->add(one, InnerMap()); 4351 outer->begin()->value.add(two, IntWrapper::create(3)); 4352 EXPECT_EQ(1u, outer->get(one).size()); 4353 if (!keepOuterAlive) 4354 one.clear(); 4355 if (!keepInnerAlive) 4356 two.clear(); 4357 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4358 if (keepOuterAlive) { 4359 const InnerMap& inner = outer->get(one); 4360 if (keepInnerAlive) { 4361 EXPECT_EQ(1u, inner.size()); 4362 IntWrapper* three = inner.get(two); 4363 EXPECT_EQ(3, three->value()); 4364 } else { 4365 EXPECT_EQ(0u, inner.size()); 4366 } 4367 } else { 4368 EXPECT_EQ(0u, outer->size()); 4369 } 4370 outer->clear(); 4371 Persistent<IntWrapper> deep = IntWrapper::create(42); 4372 Persistent<IntWrapper> home = IntWrapper::create(103); 4373 Persistent<IntWrapper> composite = IntWrapper::create(91); 4374 Persistent<HeapVector<Member<IntWrapper> > > keepAlive = new HeapVector<Member<IntWrapper> >(); 4375 for (int i = 0; i < 10000; i++) { 4376 IntWrapper* value = IntWrapper::create(i); 4377 keepAlive->append(value); 4378 OuterMap::AddResult newEntry = outer->add(value, InnerMap()); 4379 newEntry.storedValue->value.add(deep, home); 4380 newEntry.storedValue->value.add(composite, home); 4381 } 4382 composite.clear(); 4383 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4384 EXPECT_EQ(10000u, outer->size()); 4385 for (int i = 0; i < 10000; i++) { 4386 IntWrapper* value = keepAlive->at(i); 4387 EXPECT_EQ(1u, outer->get(value).size()); // Other one was deleted by weak handling. 4388 if (i & 1) 4389 keepAlive->at(i) = nullptr; 4390 } 4391 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4392 EXPECT_EQ(5000u, outer->size()); 4393 } 4394 } 4395 } 4396 4397 class EphemeronWrapper : public GarbageCollected<EphemeronWrapper> { 4398 public: 4399 void trace(Visitor* visitor) 4400 { 4401 visitor->trace(m_map); 4402 } 4403 4404 typedef HeapHashMap<WeakMember<IntWrapper>, Member<EphemeronWrapper> > Map; 4405 Map& map() { return m_map; } 4406 4407 private: 4408 Map m_map; 4409 }; 4410 4411 TEST(HeapTest, EphemeronsPointToEphemerons) 4412 { 4413 Persistent<IntWrapper> key = IntWrapper::create(42); 4414 Persistent<IntWrapper> key2 = IntWrapper::create(103); 4415 4416 Persistent<EphemeronWrapper> chain; 4417 for (int i = 0; i < 100; i++) { 4418 EphemeronWrapper* oldHead = chain; 4419 chain = new EphemeronWrapper(); 4420 if (i == 50) 4421 chain->map().add(key2, oldHead); 4422 else 4423 chain->map().add(key, oldHead); 4424 chain->map().add(IntWrapper::create(103), new EphemeronWrapper()); 4425 } 4426 4427 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4428 4429 EphemeronWrapper* wrapper = chain; 4430 for (int i = 0; i< 100; i++) { 4431 EXPECT_EQ(1u, wrapper->map().size()); 4432 if (i == 49) 4433 wrapper = wrapper->map().get(key2); 4434 else 4435 wrapper = wrapper->map().get(key); 4436 } 4437 EXPECT_EQ(nullptr, wrapper); 4438 4439 key2.clear(); 4440 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4441 4442 wrapper = chain; 4443 for (int i = 0; i < 50; i++) { 4444 EXPECT_EQ(i == 49 ? 0u : 1u, wrapper->map().size()); 4445 wrapper = wrapper->map().get(key); 4446 } 4447 EXPECT_EQ(nullptr, wrapper); 4448 4449 key.clear(); 4450 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4451 EXPECT_EQ(0u, chain->map().size()); 4452 } 4453 4454 TEST(HeapTest, Ephemeron) 4455 { 4456 typedef HeapHashMap<WeakMember<IntWrapper>, PairWithWeakHandling> WeakPairMap; 4457 typedef HeapHashMap<PairWithWeakHandling, WeakMember<IntWrapper> > PairWeakMap; 4458 typedef HeapHashSet<WeakMember<IntWrapper> > Set; 4459 4460 Persistent<WeakPairMap> weakPairMap = new WeakPairMap(); 4461 Persistent<WeakPairMap> weakPairMap2 = new WeakPairMap(); 4462 Persistent<WeakPairMap> weakPairMap3 = new WeakPairMap(); 4463 Persistent<WeakPairMap> weakPairMap4 = new WeakPairMap(); 4464 4465 Persistent<PairWeakMap> pairWeakMap = new PairWeakMap(); 4466 Persistent<PairWeakMap> pairWeakMap2 = new PairWeakMap(); 4467 4468 Persistent<Set> set = new Set(); 4469 4470 Persistent<IntWrapper> wp1 = IntWrapper::create(1); 4471 Persistent<IntWrapper> wp2 = IntWrapper::create(2); 4472 Persistent<IntWrapper> pw1 = IntWrapper::create(3); 4473 Persistent<IntWrapper> pw2 = IntWrapper::create(4); 4474 4475 weakPairMap->add(wp1, PairWithWeakHandling(wp1, wp1)); 4476 weakPairMap->add(wp2, PairWithWeakHandling(wp1, wp1)); 4477 weakPairMap2->add(wp1, PairWithWeakHandling(wp1, wp2)); 4478 weakPairMap2->add(wp2, PairWithWeakHandling(wp1, wp2)); 4479 // The map from wp1 to (wp2, wp1) would mark wp2 live, so we skip that. 4480 weakPairMap3->add(wp2, PairWithWeakHandling(wp2, wp1)); 4481 weakPairMap4->add(wp1, PairWithWeakHandling(wp2, wp2)); 4482 weakPairMap4->add(wp2, PairWithWeakHandling(wp2, wp2)); 4483 4484 pairWeakMap->add(PairWithWeakHandling(pw1, pw1), pw1); 4485 pairWeakMap->add(PairWithWeakHandling(pw1, pw2), pw1); 4486 // The map from (pw2, pw1) to pw1 would make pw2 live, so we skip that. 4487 pairWeakMap->add(PairWithWeakHandling(pw2, pw2), pw1); 4488 pairWeakMap2->add(PairWithWeakHandling(pw1, pw1), pw2); 4489 pairWeakMap2->add(PairWithWeakHandling(pw1, pw2), pw2); 4490 pairWeakMap2->add(PairWithWeakHandling(pw2, pw1), pw2); 4491 pairWeakMap2->add(PairWithWeakHandling(pw2, pw2), pw2); 4492 4493 4494 set->add(wp1); 4495 set->add(wp2); 4496 set->add(pw1); 4497 set->add(pw2); 4498 4499 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4500 4501 EXPECT_EQ(2u, weakPairMap->size()); 4502 EXPECT_EQ(2u, weakPairMap2->size()); 4503 EXPECT_EQ(1u, weakPairMap3->size()); 4504 EXPECT_EQ(2u, weakPairMap4->size()); 4505 4506 EXPECT_EQ(3u, pairWeakMap->size()); 4507 EXPECT_EQ(4u, pairWeakMap2->size()); 4508 4509 EXPECT_EQ(4u, set->size()); 4510 4511 wp2.clear(); // Kills all entries in the weakPairMaps except the first. 4512 pw2.clear(); // Kills all entries in the pairWeakMaps except the first. 4513 4514 for (int i = 0; i < 2; i++) { 4515 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4516 4517 EXPECT_EQ(1u, weakPairMap->size()); 4518 EXPECT_EQ(0u, weakPairMap2->size()); 4519 EXPECT_EQ(0u, weakPairMap3->size()); 4520 EXPECT_EQ(0u, weakPairMap4->size()); 4521 4522 EXPECT_EQ(1u, pairWeakMap->size()); 4523 EXPECT_EQ(0u, pairWeakMap2->size()); 4524 4525 EXPECT_EQ(2u, set->size()); // wp1 and pw1. 4526 } 4527 4528 wp1.clear(); 4529 pw1.clear(); 4530 4531 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4532 4533 EXPECT_EQ(0u, weakPairMap->size()); 4534 EXPECT_EQ(0u, pairWeakMap->size()); 4535 EXPECT_EQ(0u, set->size()); 4536 } 4537 4538 class Link1 : public GarbageCollected<Link1> { 4539 public: 4540 Link1(IntWrapper* link) : m_link(link) { } 4541 4542 void trace(Visitor* visitor) 4543 { 4544 visitor->trace(m_link); 4545 } 4546 4547 IntWrapper* link() { return m_link; } 4548 4549 private: 4550 Member<IntWrapper> m_link; 4551 }; 4552 4553 TEST(HeapTest, IndirectStrongToWeak) 4554 { 4555 typedef HeapHashMap<WeakMember<IntWrapper>, Member<Link1> > Map; 4556 Persistent<Map> map = new Map(); 4557 Persistent<IntWrapper> deadObject = IntWrapper::create(100); // Named for "Drowning by Numbers" (1988). 4558 Persistent<IntWrapper> lifeObject = IntWrapper::create(42); 4559 map->add(deadObject, new Link1(deadObject)); 4560 map->add(lifeObject, new Link1(lifeObject)); 4561 EXPECT_EQ(2u, map->size()); 4562 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4563 EXPECT_EQ(2u, map->size()); 4564 EXPECT_EQ(deadObject, map->get(deadObject)->link()); 4565 EXPECT_EQ(lifeObject, map->get(lifeObject)->link()); 4566 deadObject.clear(); // Now it can live up to its name. 4567 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4568 EXPECT_EQ(1u, map->size()); 4569 EXPECT_EQ(lifeObject, map->get(lifeObject)->link()); 4570 lifeObject.clear(); // Despite its name. 4571 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4572 EXPECT_EQ(0u, map->size()); 4573 } 4574 4575 static Mutex& mainThreadMutex() 4576 { 4577 AtomicallyInitializedStatic(Mutex&, mainMutex = *new Mutex); 4578 return mainMutex; 4579 } 4580 4581 static ThreadCondition& mainThreadCondition() 4582 { 4583 AtomicallyInitializedStatic(ThreadCondition&, mainCondition = *new ThreadCondition); 4584 return mainCondition; 4585 } 4586 4587 static void parkMainThread() 4588 { 4589 mainThreadCondition().wait(mainThreadMutex()); 4590 } 4591 4592 static void wakeMainThread() 4593 { 4594 MutexLocker locker(mainThreadMutex()); 4595 mainThreadCondition().signal(); 4596 } 4597 4598 static Mutex& workerThreadMutex() 4599 { 4600 AtomicallyInitializedStatic(Mutex&, workerMutex = *new Mutex); 4601 return workerMutex; 4602 } 4603 4604 static ThreadCondition& workerThreadCondition() 4605 { 4606 AtomicallyInitializedStatic(ThreadCondition&, workerCondition = *new ThreadCondition); 4607 return workerCondition; 4608 } 4609 4610 static void parkWorkerThread() 4611 { 4612 workerThreadCondition().wait(workerThreadMutex()); 4613 } 4614 4615 static void wakeWorkerThread() 4616 { 4617 MutexLocker locker(workerThreadMutex()); 4618 workerThreadCondition().signal(); 4619 } 4620 4621 class CrossThreadObject : public GarbageCollectedFinalized<CrossThreadObject> { 4622 public: 4623 static CrossThreadObject* create(IntWrapper* workerObjectPointer) 4624 { 4625 return new CrossThreadObject(workerObjectPointer); 4626 } 4627 4628 virtual ~CrossThreadObject() 4629 { 4630 ++s_destructorCalls; 4631 } 4632 4633 static int s_destructorCalls; 4634 void trace(Visitor* visitor) { visitor->trace(m_workerObject); } 4635 4636 private: 4637 CrossThreadObject(IntWrapper* workerObjectPointer) : m_workerObject(workerObjectPointer) { } 4638 4639 private: 4640 Member<IntWrapper> m_workerObject; 4641 }; 4642 4643 int CrossThreadObject::s_destructorCalls = 0; 4644 4645 class CrossThreadPointerTester { 4646 public: 4647 static void test() 4648 { 4649 CrossThreadObject::s_destructorCalls = 0; 4650 IntWrapper::s_destructorCalls = 0; 4651 4652 MutexLocker locker(mainThreadMutex()); 4653 OwnPtr<WebThread> workerThread = adoptPtr(Platform::current()->createThread("Test Worker Thread")); 4654 workerThread->postTask(new Task(WTF::bind(workerThreadMain))); 4655 4656 parkMainThread(); 4657 4658 uintptr_t stackPtrValue = 0; 4659 { 4660 // Create an object with a pointer to the other heap's IntWrapper. 4661 Persistent<CrossThreadObject> cto = CrossThreadObject::create(const_cast<IntWrapper*>(s_workerObjectPointer)); 4662 s_workerObjectPointer = 0; 4663 4664 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4665 4666 // Nothing should have been collected/destructed. 4667 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls); 4668 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 4669 4670 // Put cto into a stack value. This is used to check that a conservative 4671 // GC succeeds even though we are tracing the other thread heap after 4672 // shutting it down. 4673 stackPtrValue = reinterpret_cast<uintptr_t>(cto.get()); 4674 } 4675 // At this point it is "programatically" okay to shut down the worker thread 4676 // since the cto object should be dead. However out stackPtrValue will cause a 4677 // trace of the object when doing a conservative GC. 4678 // The worker thread's thread local GC's should just add the worker thread's 4679 // pages to the heap after finalizing IntWrapper. 4680 wakeWorkerThread(); 4681 4682 // Wait for the worker to shutdown. 4683 parkMainThread(); 4684 4685 // After the worker thread has detached it should have finalized the 4686 // IntWrapper object on its heaps. Since there has been no global GC 4687 // the cto object should not have been finalized. 4688 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls); 4689 EXPECT_EQ(1, IntWrapper::s_destructorCalls); 4690 4691 // Now do a conservative GC. The stackPtrValue should keep cto alive 4692 // and will also cause the orphaned page of the other thread to be 4693 // traced. At this point cto should still not be finalized. 4694 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 4695 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls); 4696 EXPECT_EQ(1, IntWrapper::s_destructorCalls); 4697 4698 // This release assert is here to ensure the stackValuePtr is not 4699 // optimized away before doing the above conservative GC. If the 4700 // EXPECT_EQ(0, CrossThreadObject::s_destructorCalls) call above 4701 // starts failing it means we have to find a better way to ensure 4702 // the stackPtrValue is not optimized away. 4703 RELEASE_ASSERT(stackPtrValue); 4704 4705 // Do a GC with no pointers on the stack to see the cto being collected. 4706 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4707 EXPECT_EQ(1, CrossThreadObject::s_destructorCalls); 4708 EXPECT_EQ(1, IntWrapper::s_destructorCalls); 4709 } 4710 4711 private: 4712 static void workerThreadMain() 4713 { 4714 MutexLocker locker(workerThreadMutex()); 4715 ThreadState::attach(); 4716 4717 { 4718 // Create a worker object that is only kept alive by a cross thread 4719 // pointer (from CrossThreadObject). 4720 IntWrapper* workerObject = IntWrapper::create(42); 4721 s_workerObjectPointer = workerObject; 4722 } 4723 4724 // Wake up the main thread which is waiting for the worker to do its 4725 // allocation and passing the pointer. 4726 wakeMainThread(); 4727 4728 // Wait for main thread to signal the worker to shutdown. 4729 { 4730 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack); 4731 parkWorkerThread(); 4732 } 4733 4734 ThreadState::detach(); 4735 4736 // Tell the main thread the worker has done its shutdown. 4737 wakeMainThread(); 4738 } 4739 4740 static volatile IntWrapper* s_workerObjectPointer; 4741 }; 4742 4743 volatile IntWrapper* CrossThreadPointerTester::s_workerObjectPointer = 0; 4744 4745 TEST(HeapTest, CrossThreadPointerToOrphanedPage) 4746 { 4747 CrossThreadPointerTester::test(); 4748 } 4749 4750 class DeadBitTester { 4751 public: 4752 static void test() 4753 { 4754 IntWrapper::s_destructorCalls = 0; 4755 4756 MutexLocker locker(mainThreadMutex()); 4757 OwnPtr<WebThread> workerThread = adoptPtr(Platform::current()->createThread("Test Worker Thread")); 4758 workerThread->postTask(new Task(WTF::bind(workerThreadMain))); 4759 4760 // Wait for the worker thread to have done its initialization, 4761 // IE. the worker allocates an object and then throw aways any 4762 // pointers to it. 4763 parkMainThread(); 4764 4765 // Now do a GC. This will not find the worker threads object since it 4766 // is not referred from any of the threads. Even a conservative 4767 // GC will not find it. 4768 // Also at this point the worker is waiting for the main thread 4769 // to be parked and will not do any sweep of its heap. 4770 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4771 4772 // Since the worker thread is not sweeping the worker object should 4773 // not have been finalized. 4774 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 4775 4776 // Put the worker thread's object address on the stack and do a 4777 // conservative GC. This should find the worker object, but since 4778 // it was dead in the previous GC it should not be traced in this 4779 // GC. 4780 uintptr_t stackPtrValue = s_workerObjectPointer; 4781 s_workerObjectPointer = 0; 4782 ASSERT_UNUSED(stackPtrValue, stackPtrValue); 4783 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 4784 4785 // Since the worker thread is not sweeping the worker object should 4786 // not have been finalized. 4787 EXPECT_EQ(0, IntWrapper::s_destructorCalls); 4788 4789 // Wake up the worker thread so it can continue with its sweeping. 4790 // This should finalized the worker object which we test below. 4791 // The worker thread will go back to sleep once sweeping to ensure 4792 // we don't have thread local GCs until after validating the destructor 4793 // was called. 4794 wakeWorkerThread(); 4795 4796 // Wait for the worker thread to sweep its heaps before checking. 4797 parkMainThread(); 4798 EXPECT_EQ(1, IntWrapper::s_destructorCalls); 4799 4800 // Wake up the worker to allow it thread to continue with thread 4801 // shutdown. 4802 wakeWorkerThread(); 4803 } 4804 4805 private: 4806 4807 static void workerThreadMain() 4808 { 4809 MutexLocker locker(workerThreadMutex()); 4810 4811 ThreadState::attach(); 4812 4813 { 4814 // Create a worker object that is not kept alive except the 4815 // main thread will keep it as an integer value on its stack. 4816 IntWrapper* workerObject = IntWrapper::create(42); 4817 s_workerObjectPointer = reinterpret_cast<uintptr_t>(workerObject); 4818 } 4819 4820 // Signal the main thread that the worker is done with its allocation. 4821 wakeMainThread(); 4822 4823 { 4824 // Wait for the main thread to do two GCs without sweeping this thread 4825 // heap. The worker waits within a safepoint, but there is no sweeping 4826 // until leaving the safepoint scope. 4827 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack); 4828 parkWorkerThread(); 4829 } 4830 4831 // Wake up the main thread when done sweeping. 4832 wakeMainThread(); 4833 4834 // Wait with detach until the main thread says so. This is not strictly 4835 // necessary, but it means the worker thread will not do its thread local 4836 // GCs just yet, making it easier to reason about that no new GC has occurred 4837 // and the above sweep was the one finalizing the worker object. 4838 parkWorkerThread(); 4839 4840 ThreadState::detach(); 4841 } 4842 4843 static volatile uintptr_t s_workerObjectPointer; 4844 }; 4845 4846 volatile uintptr_t DeadBitTester::s_workerObjectPointer = 0; 4847 4848 TEST(HeapTest, ObjectDeadBit) 4849 { 4850 DeadBitTester::test(); 4851 } 4852 4853 class ThreadedStrongificationTester { 4854 public: 4855 static void test() 4856 { 4857 IntWrapper::s_destructorCalls = 0; 4858 4859 MutexLocker locker(mainThreadMutex()); 4860 OwnPtr<WebThread> workerThread = adoptPtr(Platform::current()->createThread("Test Worker Thread")); 4861 workerThread->postTask(new Task(WTF::bind(workerThreadMain))); 4862 4863 // Wait for the worker thread initialization. The worker 4864 // allocates a weak collection where both collection and 4865 // contents are kept alive via persistent pointers. 4866 parkMainThread(); 4867 4868 // Perform two garbage collections where the worker thread does 4869 // not wake up in between. This will cause us to remove marks 4870 // and mark unmarked objects dead. The collection on the worker 4871 // heap is found through the persistent and the backing should 4872 // be marked. 4873 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4874 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4875 4876 // Wake up the worker thread so it can continue. It will sweep 4877 // and perform another GC where the backing store of its 4878 // collection should be strongified. 4879 wakeWorkerThread(); 4880 4881 // Wait for the worker thread to sweep its heaps before checking. 4882 { 4883 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack); 4884 parkMainThread(); 4885 } 4886 } 4887 4888 private: 4889 4890 static HeapHashSet<WeakMember<IntWrapper> >* allocateCollection() 4891 { 4892 // Create a weak collection that is kept alive by a persistent 4893 // and keep the contents alive with a persistents as 4894 // well. 4895 Persistent<IntWrapper> wrapper1 = IntWrapper::create(32); 4896 Persistent<IntWrapper> wrapper2 = IntWrapper::create(32); 4897 Persistent<IntWrapper> wrapper3 = IntWrapper::create(32); 4898 Persistent<IntWrapper> wrapper4 = IntWrapper::create(32); 4899 Persistent<IntWrapper> wrapper5 = IntWrapper::create(32); 4900 Persistent<IntWrapper> wrapper6 = IntWrapper::create(32); 4901 Persistent<HeapHashSet<WeakMember<IntWrapper> > > weakCollection = new HeapHashSet<WeakMember<IntWrapper> >; 4902 weakCollection->add(wrapper1); 4903 weakCollection->add(wrapper2); 4904 weakCollection->add(wrapper3); 4905 weakCollection->add(wrapper4); 4906 weakCollection->add(wrapper5); 4907 weakCollection->add(wrapper6); 4908 4909 // Signal the main thread that the worker is done with its allocation. 4910 wakeMainThread(); 4911 4912 { 4913 // Wait for the main thread to do two GCs without sweeping 4914 // this thread heap. The worker waits within a safepoint, 4915 // but there is no sweeping until leaving the safepoint 4916 // scope. If the weak collection backing is marked dead 4917 // because of this we will not get strongification in the 4918 // GC we force when we continue. 4919 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack); 4920 parkWorkerThread(); 4921 } 4922 4923 return weakCollection; 4924 } 4925 4926 static void workerThreadMain() 4927 { 4928 MutexLocker locker(workerThreadMutex()); 4929 4930 ThreadState::attach(); 4931 4932 { 4933 Persistent<HeapHashSet<WeakMember<IntWrapper> > > collection = allocateCollection(); 4934 { 4935 // Prevent weak processing with an iterator and GC. 4936 HeapHashSet<WeakMember<IntWrapper> >::iterator it = collection->begin(); 4937 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 4938 4939 // The backing should be strongified because of the iterator. 4940 EXPECT_EQ(6u, collection->size()); 4941 EXPECT_EQ(32, (*it)->value()); 4942 } 4943 4944 // Disregarding the iterator but keeping the collection alive 4945 // with a persistent should lead to weak processing. 4946 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4947 EXPECT_EQ(0u, collection->size()); 4948 } 4949 4950 wakeMainThread(); 4951 ThreadState::detach(); 4952 } 4953 4954 static volatile uintptr_t s_workerObjectPointer; 4955 }; 4956 4957 TEST(HeapTest, ThreadedStrongification) 4958 { 4959 ThreadedStrongificationTester::test(); 4960 } 4961 4962 static bool allocateAndReturnBool() 4963 { 4964 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 4965 return true; 4966 } 4967 4968 class MixinWithGarbageCollectionInConstructor : public GarbageCollectedMixin { 4969 public: 4970 MixinWithGarbageCollectionInConstructor() : m_dummy(allocateAndReturnBool()) 4971 { 4972 } 4973 private: 4974 bool m_dummy; 4975 }; 4976 4977 class ClassWithGarbageCollectingMixinConstructor 4978 : public GarbageCollected<ClassWithGarbageCollectingMixinConstructor> 4979 , public MixinWithGarbageCollectionInConstructor { 4980 USING_GARBAGE_COLLECTED_MIXIN(ClassWithGarbageCollectingMixinConstructor); 4981 public: 4982 ClassWithGarbageCollectingMixinConstructor() : m_wrapper(IntWrapper::create(32)) 4983 { 4984 } 4985 4986 virtual void trace(Visitor* visitor) 4987 { 4988 visitor->trace(m_wrapper); 4989 } 4990 4991 void verify() 4992 { 4993 EXPECT_EQ(32, m_wrapper->value()); 4994 } 4995 4996 private: 4997 Member<IntWrapper> m_wrapper; 4998 }; 4999 5000 // Regression test for out of bounds call through vtable. 5001 // Passes if it doesn't crash. 5002 TEST(HeapTest, GarbageCollectionDuringMixinConstruction) 5003 { 5004 ClassWithGarbageCollectingMixinConstructor* a = 5005 new ClassWithGarbageCollectingMixinConstructor(); 5006 a->verify(); 5007 } 5008 5009 static RecursiveMutex& recursiveMutex() 5010 { 5011 AtomicallyInitializedStatic(RecursiveMutex&, recursiveMutex = *new RecursiveMutex); 5012 return recursiveMutex; 5013 } 5014 5015 class DestructorLockingObject : public GarbageCollectedFinalized<DestructorLockingObject> { 5016 public: 5017 static DestructorLockingObject* create() 5018 { 5019 return new DestructorLockingObject(); 5020 } 5021 5022 virtual ~DestructorLockingObject() 5023 { 5024 SafePointAwareMutexLocker lock(recursiveMutex()); 5025 ++s_destructorCalls; 5026 } 5027 5028 static int s_destructorCalls; 5029 void trace(Visitor* visitor) { } 5030 5031 private: 5032 DestructorLockingObject() { } 5033 }; 5034 5035 int DestructorLockingObject::s_destructorCalls = 0; 5036 5037 class RecursiveLockingTester { 5038 public: 5039 static void test() 5040 { 5041 DestructorLockingObject::s_destructorCalls = 0; 5042 5043 MutexLocker locker(mainThreadMutex()); 5044 OwnPtr<WebThread> workerThread = adoptPtr(Platform::current()->createThread("Test Worker Thread")); 5045 workerThread->postTask(new Task(WTF::bind(workerThreadMain))); 5046 5047 // Park the main thread until the worker thread has initialized. 5048 parkMainThread(); 5049 5050 { 5051 SafePointAwareMutexLocker recursiveLocker(recursiveMutex()); 5052 5053 // Let the worker try to acquire the above mutex. It won't get it 5054 // until the main thread has done its GC. 5055 wakeWorkerThread(); 5056 5057 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 5058 5059 // The worker thread should not have swept yet since it is waiting 5060 // to get the global mutex. 5061 EXPECT_EQ(0, DestructorLockingObject::s_destructorCalls); 5062 } 5063 // At this point the main thread releases the global lock and the worker 5064 // can acquire it and do its sweep of its heaps. Just wait for the worker 5065 // to complete its sweep and check the result. 5066 parkMainThread(); 5067 EXPECT_EQ(1, DestructorLockingObject::s_destructorCalls); 5068 } 5069 5070 private: 5071 static void workerThreadMain() 5072 { 5073 MutexLocker locker(workerThreadMutex()); 5074 ThreadState::attach(); 5075 5076 DestructorLockingObject* dlo = DestructorLockingObject::create(); 5077 ASSERT_UNUSED(dlo, dlo); 5078 5079 // Wake up the main thread which is waiting for the worker to do its 5080 // allocation. 5081 wakeMainThread(); 5082 5083 // Wait for the main thread to get the global lock to ensure it has 5084 // it before the worker tries to acquire it. We want the worker to 5085 // block in the SafePointAwareMutexLocker until the main thread 5086 // has done a GC. The GC will not mark the "dlo" object since the worker 5087 // is entering the safepoint with NoHeapPointersOnStack. When the worker 5088 // subsequently gets the global lock and leaves the safepoint it will 5089 // sweep its heap and finalize "dlo". The destructor of "dlo" will try 5090 // to acquire the same global lock that the thread just got and deadlock 5091 // unless the global lock is recursive. 5092 parkWorkerThread(); 5093 SafePointAwareMutexLocker recursiveLocker(recursiveMutex(), ThreadState::NoHeapPointersOnStack); 5094 5095 // We won't get here unless the lock is recursive since the sweep done 5096 // in the constructor of SafePointAwareMutexLocker after 5097 // getting the lock will not complete given the "dlo" destructor is 5098 // waiting to get the same lock. 5099 // Tell the main thread the worker has done its sweep. 5100 wakeMainThread(); 5101 5102 ThreadState::detach(); 5103 } 5104 5105 static volatile IntWrapper* s_workerObjectPointer; 5106 }; 5107 5108 TEST(HeapTest, RecursiveMutex) 5109 { 5110 RecursiveLockingTester::test(); 5111 } 5112 5113 template<typename T> 5114 class TraceIfNeededTester : public GarbageCollectedFinalized<TraceIfNeededTester<T> > { 5115 public: 5116 static TraceIfNeededTester<T>* create() { return new TraceIfNeededTester<T>(); } 5117 static TraceIfNeededTester<T>* create(const T& obj) { return new TraceIfNeededTester<T>(obj); } 5118 void trace(Visitor* visitor) { TraceIfNeeded<T>::trace(visitor, &m_obj); } 5119 T& obj() { return m_obj; } 5120 ~TraceIfNeededTester() { } 5121 private: 5122 TraceIfNeededTester() { } 5123 explicit TraceIfNeededTester(const T& obj) : m_obj(obj) { } 5124 T m_obj; 5125 }; 5126 5127 class PartObject { 5128 DISALLOW_ALLOCATION(); 5129 public: 5130 PartObject() : m_obj(SimpleObject::create()) { } 5131 void trace(Visitor* visitor) { visitor->trace(m_obj); } 5132 private: 5133 Member<SimpleObject> m_obj; 5134 }; 5135 5136 TEST(HeapTest, TraceIfNeeded) 5137 { 5138 CountingVisitor visitor; 5139 5140 { 5141 TraceIfNeededTester<RefPtr<OffHeapInt> >* m_offHeap = TraceIfNeededTester<RefPtr<OffHeapInt> >::create(OffHeapInt::create(42)); 5142 visitor.reset(); 5143 m_offHeap->trace(&visitor); 5144 EXPECT_EQ(0u, visitor.count()); 5145 } 5146 5147 { 5148 TraceIfNeededTester<PartObject>* m_part = TraceIfNeededTester<PartObject>::create(); 5149 visitor.reset(); 5150 m_part->trace(&visitor); 5151 EXPECT_EQ(1u, visitor.count()); 5152 } 5153 5154 { 5155 TraceIfNeededTester<Member<SimpleObject> >* m_obj = TraceIfNeededTester<Member<SimpleObject> >::create(Member<SimpleObject>(SimpleObject::create())); 5156 visitor.reset(); 5157 m_obj->trace(&visitor); 5158 EXPECT_EQ(1u, visitor.count()); 5159 } 5160 5161 { 5162 TraceIfNeededTester<HeapVector<Member<SimpleObject> > >* m_vec = TraceIfNeededTester<HeapVector<Member<SimpleObject> > >::create(); 5163 m_vec->obj().append(SimpleObject::create()); 5164 visitor.reset(); 5165 m_vec->trace(&visitor); 5166 EXPECT_EQ(2u, visitor.count()); 5167 } 5168 } 5169 5170 class AllocatesOnAssignment { 5171 public: 5172 AllocatesOnAssignment(std::nullptr_t) 5173 : m_value(nullptr) 5174 { } 5175 AllocatesOnAssignment(int x) 5176 : m_value(new IntWrapper(x)) 5177 { } 5178 AllocatesOnAssignment(IntWrapper* x) 5179 : m_value(x) 5180 { } 5181 5182 AllocatesOnAssignment& operator=(const AllocatesOnAssignment x) 5183 { 5184 m_value = x.m_value; 5185 return *this; 5186 } 5187 5188 enum DeletedMarker { 5189 DeletedValue 5190 }; 5191 5192 AllocatesOnAssignment(const AllocatesOnAssignment& other) 5193 { 5194 Heap::collectGarbage(ThreadState::HeapPointersOnStack); 5195 m_value = new IntWrapper(other.m_value->value()); 5196 } 5197 5198 AllocatesOnAssignment(DeletedMarker) 5199 : m_value(reinterpret_cast<IntWrapper*>(-1)) { } 5200 5201 inline bool isDeleted() const { return m_value == reinterpret_cast<IntWrapper*>(-1); } 5202 5203 virtual void trace(Visitor* visitor) 5204 { 5205 visitor->trace(m_value); 5206 } 5207 5208 int value() { return m_value->value(); } 5209 5210 private: 5211 Member<IntWrapper> m_value; 5212 5213 friend bool operator==(const AllocatesOnAssignment&, const AllocatesOnAssignment&); 5214 friend void swap(AllocatesOnAssignment&, AllocatesOnAssignment&); 5215 }; 5216 5217 bool operator==(const AllocatesOnAssignment& a, const AllocatesOnAssignment& b) 5218 { 5219 if (a.m_value) 5220 return b.m_value && a.m_value->value() == b.m_value->value(); 5221 return !b.m_value; 5222 } 5223 5224 void swap(AllocatesOnAssignment& a, AllocatesOnAssignment& b) 5225 { 5226 std::swap(a.m_value, b.m_value); 5227 } 5228 5229 struct DegenerateHash { 5230 static unsigned hash(const AllocatesOnAssignment&) { return 0; } 5231 static bool equal(const AllocatesOnAssignment& a, const AllocatesOnAssignment& b) { return !a.isDeleted() && a == b; } 5232 static const bool safeToCompareToEmptyOrDeleted = true; 5233 }; 5234 5235 struct AllocatesOnAssignmentHashTraits : WTF::GenericHashTraits<AllocatesOnAssignment> { 5236 typedef AllocatesOnAssignment T; 5237 typedef std::nullptr_t EmptyValueType; 5238 static EmptyValueType emptyValue() { return nullptr; } 5239 static const bool emptyValueIsZero = false; // Can't be zero if it has a vtable. 5240 static const bool needsDestruction = false; 5241 static void constructDeletedValue(T& slot, bool) { slot = T(AllocatesOnAssignment::DeletedValue); } 5242 static bool isDeletedValue(const T& value) { return value.isDeleted(); } 5243 }; 5244 5245 } // namespace blink 5246 5247 namespace WTF { 5248 5249 template<> struct DefaultHash<blink::AllocatesOnAssignment> { 5250 typedef blink::DegenerateHash Hash; 5251 }; 5252 5253 template <> struct HashTraits<blink::AllocatesOnAssignment> : blink::AllocatesOnAssignmentHashTraits { }; 5254 5255 } // namespace WTF 5256 5257 namespace blink { 5258 5259 TEST(HeapTest, GCInHashMapOperations) 5260 { 5261 typedef HeapHashMap<AllocatesOnAssignment, AllocatesOnAssignment> Map; 5262 Map* map = new Map(); 5263 IntWrapper* key = new IntWrapper(42); 5264 map->add(key, AllocatesOnAssignment(103)); 5265 map->remove(key); 5266 for (int i = 0; i < 10; i++) 5267 map->add(AllocatesOnAssignment(i), AllocatesOnAssignment(i)); 5268 for (Map::iterator it = map->begin(); it != map->end(); ++it) 5269 EXPECT_EQ(it->key.value(), it->value.value()); 5270 } 5271 5272 class PartObjectWithVirtualMethod { 5273 public: 5274 virtual void trace(Visitor*) { } 5275 }; 5276 5277 class ObjectWithVirtualPartObject : public GarbageCollected<ObjectWithVirtualPartObject> { 5278 public: 5279 ObjectWithVirtualPartObject() : m_dummy(allocateAndReturnBool()) { } 5280 void trace(Visitor* visitor) { visitor->trace(m_part); } 5281 private: 5282 bool m_dummy; 5283 PartObjectWithVirtualMethod m_part; 5284 }; 5285 5286 TEST(HeapTest, PartObjectWithVirtualMethod) 5287 { 5288 ObjectWithVirtualPartObject* object = new ObjectWithVirtualPartObject(); 5289 EXPECT_TRUE(object); 5290 } 5291 5292 class AllocInSuperConstructorArgumentSuper : public GarbageCollectedFinalized<AllocInSuperConstructorArgumentSuper> { 5293 public: 5294 AllocInSuperConstructorArgumentSuper(bool value) : m_value(value) { } 5295 virtual void trace(Visitor*) { } 5296 bool value() { return m_value; } 5297 private: 5298 bool m_value; 5299 }; 5300 5301 class AllocInSuperConstructorArgument : public AllocInSuperConstructorArgumentSuper { 5302 public: 5303 AllocInSuperConstructorArgument() 5304 : AllocInSuperConstructorArgumentSuper(allocateAndReturnBool()) 5305 { 5306 } 5307 }; 5308 5309 // Regression test for crbug.com/404511. Tests conservative marking of 5310 // an object with an uninitialized vtable. 5311 TEST(HeapTest, AllocationInSuperConstructorArgument) 5312 { 5313 AllocInSuperConstructorArgument* object = new AllocInSuperConstructorArgument(); 5314 EXPECT_TRUE(object); 5315 Heap::collectAllGarbage(); 5316 } 5317 5318 class NonNodeAllocatingNodeInDestructor : public GarbageCollectedFinalized<NonNodeAllocatingNodeInDestructor> { 5319 public: 5320 ~NonNodeAllocatingNodeInDestructor() 5321 { 5322 s_node = new Persistent<Node>(Node::create(10)); 5323 } 5324 5325 void trace(Visitor*) { } 5326 5327 static Persistent<Node>* s_node; 5328 }; 5329 5330 Persistent<Node>* NonNodeAllocatingNodeInDestructor::s_node = 0; 5331 5332 TEST(HeapTest, NonNodeAllocatingNodeInDestructor) 5333 { 5334 new NonNodeAllocatingNodeInDestructor(); 5335 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 5336 EXPECT_EQ(10, (*NonNodeAllocatingNodeInDestructor::s_node)->value()); 5337 delete NonNodeAllocatingNodeInDestructor::s_node; 5338 NonNodeAllocatingNodeInDestructor::s_node = 0; 5339 } 5340 5341 } // namespace blink 5342