| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 | 175 |
| 176 typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper>> StrongWeakPair; | 176 typedef std::pair<Member<IntWrapper>, WeakMember<IntWrapper>> StrongWeakPair; |
| 177 | 177 |
| 178 struct PairWithWeakHandling : public StrongWeakPair { | 178 struct PairWithWeakHandling : public StrongWeakPair { |
| 179 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); | 179 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); |
| 180 | 180 |
| 181 public: | 181 public: |
| 182 // Regular constructor. | 182 // Regular constructor. |
| 183 PairWithWeakHandling(IntWrapper* one, IntWrapper* two) | 183 PairWithWeakHandling(IntWrapper* one, IntWrapper* two) |
| 184 : StrongWeakPair(one, two) { | 184 : StrongWeakPair(one, two) { |
| 185 ASSERT(one); // We use null first field to indicate empty slots in the hash | 185 DCHECK(one); // We use null first field to indicate empty slots in the hash |
| 186 // table. | 186 // table. |
| 187 } | 187 } |
| 188 | 188 |
| 189 // The HashTable (via the HashTrait) calls this constructor with a | 189 // The HashTable (via the HashTrait) calls this constructor with a |
| 190 // placement new to mark slots in the hash table as being deleted. We will | 190 // placement new to mark slots in the hash table as being deleted. We will |
| 191 // never call trace or the destructor on these slots. We mark ourselves | 191 // never call trace or the destructor on these slots. We mark ourselves |
| 192 // deleted | 192 // deleted |
| 193 // with a pointer to -1 in the first field. | 193 // with a pointer to -1 in the first field. |
| 194 PairWithWeakHandling(WTF::HashTableDeletedValueType) | 194 PairWithWeakHandling(WTF::HashTableDeletedValueType) |
| 195 : StrongWeakPair(reinterpret_cast<IntWrapper*>(-1), nullptr) {} | 195 : StrongWeakPair(reinterpret_cast<IntWrapper*>(-1), nullptr) {} |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 : public SimpleClassHashTraits<blink::KeyWithCopyingMoveConstructor> {}; | 325 : public SimpleClassHashTraits<blink::KeyWithCopyingMoveConstructor> {}; |
| 326 | 326 |
| 327 } // namespace WTF | 327 } // namespace WTF |
| 328 | 328 |
| 329 namespace blink { | 329 namespace blink { |
| 330 | 330 |
| 331 class TestGCScope { | 331 class TestGCScope { |
| 332 public: | 332 public: |
| 333 explicit TestGCScope(BlinkGC::StackState state) | 333 explicit TestGCScope(BlinkGC::StackState state) |
| 334 : state_(ThreadState::Current()), safe_point_scope_(state) { | 334 : state_(ThreadState::Current()), safe_point_scope_(state) { |
| 335 ASSERT(state_->CheckThread()); | 335 DCHECK(state_->CheckThread()); |
| 336 state_->PreGC(); | 336 state_->PreGC(); |
| 337 } | 337 } |
| 338 | 338 |
| 339 ~TestGCScope() { | 339 ~TestGCScope() { |
| 340 state_->PostGC(BlinkGC::kGCWithSweep); | 340 state_->PostGC(BlinkGC::kGCWithSweep); |
| 341 state_->PreSweep(BlinkGC::kGCWithSweep); | 341 state_->PreSweep(BlinkGC::kGCWithSweep); |
| 342 } | 342 } |
| 343 | 343 |
| 344 private: | 344 private: |
| 345 ThreadState* state_; | 345 ThreadState* state_; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 const int ThreadedTesterBase::kNumberOfThreads; | 511 const int ThreadedTesterBase::kNumberOfThreads; |
| 512 | 512 |
| 513 class ThreadedHeapTester : public ThreadedTesterBase { | 513 class ThreadedHeapTester : public ThreadedTesterBase { |
| 514 public: | 514 public: |
| 515 static void Test() { ThreadedTesterBase::Test(new ThreadedHeapTester); } | 515 static void Test() { ThreadedTesterBase::Test(new ThreadedHeapTester); } |
| 516 | 516 |
| 517 ~ThreadedHeapTester() override { | 517 ~ThreadedHeapTester() override { |
| 518 // Verify that the threads cleared their CTPs when | 518 // Verify that the threads cleared their CTPs when |
| 519 // terminating, preventing access to a finalized heap. | 519 // terminating, preventing access to a finalized heap. |
| 520 for (auto& global_int_wrapper : cross_persistents_) { | 520 for (auto& global_int_wrapper : cross_persistents_) { |
| 521 ASSERT(global_int_wrapper.get()); | 521 DCHECK(global_int_wrapper.get()); |
| 522 EXPECT_FALSE(global_int_wrapper.get()->Get()); | 522 EXPECT_FALSE(global_int_wrapper.get()->Get()); |
| 523 } | 523 } |
| 524 } | 524 } |
| 525 | 525 |
| 526 protected: | 526 protected: |
| 527 using GlobalIntWrapperPersistent = CrossThreadPersistent<IntWrapper>; | 527 using GlobalIntWrapperPersistent = CrossThreadPersistent<IntWrapper>; |
| 528 | 528 |
| 529 Mutex mutex_; | 529 Mutex mutex_; |
| 530 Vector<std::unique_ptr<GlobalIntWrapperPersistent>> cross_persistents_; | 530 Vector<std::unique_ptr<GlobalIntWrapperPersistent>> cross_persistents_; |
| 531 | 531 |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 930 : public GarbageCollectedFinalized<RefCountedAndGarbageCollected> { | 930 : public GarbageCollectedFinalized<RefCountedAndGarbageCollected> { |
| 931 public: | 931 public: |
| 932 static RefCountedAndGarbageCollected* Create() { | 932 static RefCountedAndGarbageCollected* Create() { |
| 933 return new RefCountedAndGarbageCollected; | 933 return new RefCountedAndGarbageCollected; |
| 934 } | 934 } |
| 935 | 935 |
| 936 ~RefCountedAndGarbageCollected() { ++destructor_calls_; } | 936 ~RefCountedAndGarbageCollected() { ++destructor_calls_; } |
| 937 | 937 |
| 938 void Ref() { | 938 void Ref() { |
| 939 if (UNLIKELY(!ref_count_)) { | 939 if (UNLIKELY(!ref_count_)) { |
| 940 ASSERT(ThreadState::Current()->FindPageFromAddress( | 940 #if DCHECK_IS_ON() |
| 941 DCHECK(ThreadState::Current()->FindPageFromAddress( |
| 941 reinterpret_cast<Address>(this))); | 942 reinterpret_cast<Address>(this))); |
| 943 #endif |
| 942 keep_alive_ = this; | 944 keep_alive_ = this; |
| 943 } | 945 } |
| 944 ++ref_count_; | 946 ++ref_count_; |
| 945 } | 947 } |
| 946 | 948 |
| 947 void Deref() { | 949 void Deref() { |
| 948 ASSERT(ref_count_ > 0); | 950 DCHECK_GT(ref_count_, 0); |
| 949 if (!--ref_count_) | 951 if (!--ref_count_) |
| 950 keep_alive_.Clear(); | 952 keep_alive_.Clear(); |
| 951 } | 953 } |
| 952 | 954 |
| 953 DEFINE_INLINE_TRACE() {} | 955 DEFINE_INLINE_TRACE() {} |
| 954 | 956 |
| 955 static int destructor_calls_; | 957 static int destructor_calls_; |
| 956 | 958 |
| 957 private: | 959 private: |
| 958 RefCountedAndGarbageCollected() : ref_count_(0) {} | 960 RefCountedAndGarbageCollected() : ref_count_(0) {} |
| 959 | 961 |
| 960 int ref_count_; | 962 int ref_count_; |
| 961 SelfKeepAlive<RefCountedAndGarbageCollected> keep_alive_; | 963 SelfKeepAlive<RefCountedAndGarbageCollected> keep_alive_; |
| 962 }; | 964 }; |
| 963 | 965 |
| 964 int RefCountedAndGarbageCollected::destructor_calls_ = 0; | 966 int RefCountedAndGarbageCollected::destructor_calls_ = 0; |
| 965 | 967 |
| 966 class RefCountedAndGarbageCollected2 | 968 class RefCountedAndGarbageCollected2 |
| 967 : public HeapTestOtherSuperClass, | 969 : public HeapTestOtherSuperClass, |
| 968 public GarbageCollectedFinalized<RefCountedAndGarbageCollected2> { | 970 public GarbageCollectedFinalized<RefCountedAndGarbageCollected2> { |
| 969 public: | 971 public: |
| 970 static RefCountedAndGarbageCollected2* Create() { | 972 static RefCountedAndGarbageCollected2* Create() { |
| 971 return new RefCountedAndGarbageCollected2; | 973 return new RefCountedAndGarbageCollected2; |
| 972 } | 974 } |
| 973 | 975 |
| 974 ~RefCountedAndGarbageCollected2() { ++destructor_calls_; } | 976 ~RefCountedAndGarbageCollected2() { ++destructor_calls_; } |
| 975 | 977 |
| 976 void Ref() { | 978 void Ref() { |
| 977 if (UNLIKELY(!ref_count_)) { | 979 if (UNLIKELY(!ref_count_)) { |
| 978 ASSERT(ThreadState::Current()->FindPageFromAddress( | 980 #if DCHECK_IS_ON() |
| 981 DCHECK(ThreadState::Current()->FindPageFromAddress( |
| 979 reinterpret_cast<Address>(this))); | 982 reinterpret_cast<Address>(this))); |
| 983 #endif |
| 980 keep_alive_ = this; | 984 keep_alive_ = this; |
| 981 } | 985 } |
| 982 ++ref_count_; | 986 ++ref_count_; |
| 983 } | 987 } |
| 984 | 988 |
| 985 void Deref() { | 989 void Deref() { |
| 986 ASSERT(ref_count_ > 0); | 990 DCHECK_GT(ref_count_, 0); |
| 987 if (!--ref_count_) | 991 if (!--ref_count_) |
| 988 keep_alive_.Clear(); | 992 keep_alive_.Clear(); |
| 989 } | 993 } |
| 990 | 994 |
| 991 DEFINE_INLINE_TRACE() {} | 995 DEFINE_INLINE_TRACE() {} |
| 992 | 996 |
| 993 static int destructor_calls_; | 997 static int destructor_calls_; |
| 994 | 998 |
| 995 private: | 999 private: |
| 996 RefCountedAndGarbageCollected2() : ref_count_(0) {} | 1000 RefCountedAndGarbageCollected2() : ref_count_(0) {} |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1208 did_call_will_finalize_ = true; | 1212 did_call_will_finalize_ = true; |
| 1209 } | 1213 } |
| 1210 | 1214 |
| 1211 static ObserverMap& Observe(Observable& target) { | 1215 static ObserverMap& Observe(Observable& target) { |
| 1212 ObserverMap& map = Observers(); | 1216 ObserverMap& map = Observers(); |
| 1213 ObserverMap::AddResult result = map.insert(&target, nullptr); | 1217 ObserverMap::AddResult result = map.insert(&target, nullptr); |
| 1214 if (result.is_new_entry) { | 1218 if (result.is_new_entry) { |
| 1215 result.stored_value->value = | 1219 result.stored_value->value = |
| 1216 WTF::MakeUnique<FinalizationObserverWithHashMap>(target); | 1220 WTF::MakeUnique<FinalizationObserverWithHashMap>(target); |
| 1217 } else { | 1221 } else { |
| 1218 ASSERT(result.stored_value->value); | 1222 DCHECK(result.stored_value->value); |
| 1219 } | 1223 } |
| 1220 return map; | 1224 return map; |
| 1221 } | 1225 } |
| 1222 | 1226 |
| 1223 static void ClearObservers() { | 1227 static void ClearObservers() { |
| 1224 delete observer_map_; | 1228 delete observer_map_; |
| 1225 observer_map_ = nullptr; | 1229 observer_map_ = nullptr; |
| 1226 } | 1230 } |
| 1227 | 1231 |
| 1228 static bool did_call_will_finalize_; | 1232 static bool did_call_will_finalize_; |
| (...skipping 855 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2084 EXPECT_EQ(1u, Bar::live_); | 2088 EXPECT_EQ(1u, Bar::live_); |
| 2085 } | 2089 } |
| 2086 PreciselyCollectGarbage(); | 2090 PreciselyCollectGarbage(); |
| 2087 EXPECT_EQ(0u, Bar::live_); | 2091 EXPECT_EQ(0u, Bar::live_); |
| 2088 } | 2092 } |
| 2089 | 2093 |
| 2090 TEST(HeapTest, MarkTest) { | 2094 TEST(HeapTest, MarkTest) { |
| 2091 { | 2095 { |
| 2092 Bar::live_ = 0; | 2096 Bar::live_ = 0; |
| 2093 Persistent<Bar> bar = Bar::Create(); | 2097 Persistent<Bar> bar = Bar::Create(); |
| 2094 ASSERT(ThreadState::Current()->FindPageFromAddress(bar)); | 2098 #if DCHECK_IS_ON() |
| 2099 DCHECK(ThreadState::Current()->FindPageFromAddress(bar)); |
| 2100 #endif |
| 2095 EXPECT_EQ(1u, Bar::live_); | 2101 EXPECT_EQ(1u, Bar::live_); |
| 2096 { | 2102 { |
| 2097 Foo* foo = Foo::Create(bar); | 2103 Foo* foo = Foo::Create(bar); |
| 2098 ASSERT(ThreadState::Current()->FindPageFromAddress(foo)); | 2104 #if DCHECK_IS_ON() |
| 2105 DCHECK(ThreadState::Current()->FindPageFromAddress(foo)); |
| 2106 #endif |
| 2099 EXPECT_EQ(2u, Bar::live_); | 2107 EXPECT_EQ(2u, Bar::live_); |
| 2100 EXPECT_TRUE(reinterpret_cast<Address>(foo) != | 2108 EXPECT_TRUE(reinterpret_cast<Address>(foo) != |
| 2101 reinterpret_cast<Address>(bar.Get())); | 2109 reinterpret_cast<Address>(bar.Get())); |
| 2102 ConservativelyCollectGarbage(); | 2110 ConservativelyCollectGarbage(); |
| 2103 EXPECT_TRUE(foo != bar); // To make sure foo is kept alive. | 2111 EXPECT_TRUE(foo != bar); // To make sure foo is kept alive. |
| 2104 EXPECT_EQ(2u, Bar::live_); | 2112 EXPECT_EQ(2u, Bar::live_); |
| 2105 } | 2113 } |
| 2106 PreciselyCollectGarbage(); | 2114 PreciselyCollectGarbage(); |
| 2107 EXPECT_EQ(1u, Bar::live_); | 2115 EXPECT_EQ(1u, Bar::live_); |
| 2108 } | 2116 } |
| 2109 PreciselyCollectGarbage(); | 2117 PreciselyCollectGarbage(); |
| 2110 EXPECT_EQ(0u, Bar::live_); | 2118 EXPECT_EQ(0u, Bar::live_); |
| 2111 } | 2119 } |
| 2112 | 2120 |
| 2113 TEST(HeapTest, DeepTest) { | 2121 TEST(HeapTest, DeepTest) { |
| 2114 const unsigned kDepth = 100000; | 2122 const unsigned kDepth = 100000; |
| 2115 Bar::live_ = 0; | 2123 Bar::live_ = 0; |
| 2116 { | 2124 { |
| 2117 Bar* bar = Bar::Create(); | 2125 Bar* bar = Bar::Create(); |
| 2118 ASSERT(ThreadState::Current()->FindPageFromAddress(bar)); | 2126 #if DCHECK_IS_ON() |
| 2127 DCHECK(ThreadState::Current()->FindPageFromAddress(bar)); |
| 2128 #endif |
| 2119 Foo* foo = Foo::Create(bar); | 2129 Foo* foo = Foo::Create(bar); |
| 2120 ASSERT(ThreadState::Current()->FindPageFromAddress(foo)); | 2130 #if DCHECK_IS_ON() |
| 2131 DCHECK(ThreadState::Current()->FindPageFromAddress(foo)); |
| 2132 #endif |
| 2121 EXPECT_EQ(2u, Bar::live_); | 2133 EXPECT_EQ(2u, Bar::live_); |
| 2122 for (unsigned i = 0; i < kDepth; i++) { | 2134 for (unsigned i = 0; i < kDepth; i++) { |
| 2123 Foo* foo2 = Foo::Create(foo); | 2135 Foo* foo2 = Foo::Create(foo); |
| 2124 foo = foo2; | 2136 foo = foo2; |
| 2125 ASSERT(ThreadState::Current()->FindPageFromAddress(foo)); | 2137 #if DCHECK_IS_ON() |
| 2138 DCHECK(ThreadState::Current()->FindPageFromAddress(foo)); |
| 2139 #endif |
| 2126 } | 2140 } |
| 2127 EXPECT_EQ(kDepth + 2, Bar::live_); | 2141 EXPECT_EQ(kDepth + 2, Bar::live_); |
| 2128 ConservativelyCollectGarbage(); | 2142 ConservativelyCollectGarbage(); |
| 2129 EXPECT_TRUE(foo != bar); // To make sure foo and bar are kept alive. | 2143 EXPECT_TRUE(foo != bar); // To make sure foo and bar are kept alive. |
| 2130 EXPECT_EQ(kDepth + 2, Bar::live_); | 2144 EXPECT_EQ(kDepth + 2, Bar::live_); |
| 2131 } | 2145 } |
| 2132 PreciselyCollectGarbage(); | 2146 PreciselyCollectGarbage(); |
| 2133 EXPECT_EQ(0u, Bar::live_); | 2147 EXPECT_EQ(0u, Bar::live_); |
| 2134 } | 2148 } |
| 2135 | 2149 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2258 ThreadHeap& heap = ThreadState::Current()->Heap(); | 2272 ThreadHeap& heap = ThreadState::Current()->Heap(); |
| 2259 ClearOutOldGarbage(); | 2273 ClearOutOldGarbage(); |
| 2260 size_t initial_object_payload_size = heap.ObjectPayloadSizeForTesting(); | 2274 size_t initial_object_payload_size = heap.ObjectPayloadSizeForTesting(); |
| 2261 size_t initial_allocated_space = heap.HeapStats().AllocatedSpace(); | 2275 size_t initial_allocated_space = heap.HeapStats().AllocatedSpace(); |
| 2262 IntWrapper::destructor_calls_ = 0; | 2276 IntWrapper::destructor_calls_ = 0; |
| 2263 LargeHeapObject::destructor_calls_ = 0; | 2277 LargeHeapObject::destructor_calls_ = 0; |
| 2264 { | 2278 { |
| 2265 int slack = | 2279 int slack = |
| 2266 8; // LargeHeapObject points to an IntWrapper that is also allocated. | 2280 8; // LargeHeapObject points to an IntWrapper that is also allocated. |
| 2267 Persistent<LargeHeapObject> object = LargeHeapObject::Create(); | 2281 Persistent<LargeHeapObject> object = LargeHeapObject::Create(); |
| 2268 ASSERT(ThreadState::Current()->FindPageFromAddress(object)); | 2282 #if DCHECK_IS_ON() |
| 2269 ASSERT(ThreadState::Current()->FindPageFromAddress( | 2283 DCHECK(ThreadState::Current()->FindPageFromAddress(object)); |
| 2284 DCHECK(ThreadState::Current()->FindPageFromAddress( |
| 2270 reinterpret_cast<char*>(object.Get()) + sizeof(LargeHeapObject) - 1)); | 2285 reinterpret_cast<char*>(object.Get()) + sizeof(LargeHeapObject) - 1)); |
| 2286 #endif |
| 2271 ClearOutOldGarbage(); | 2287 ClearOutOldGarbage(); |
| 2272 size_t after_allocation = heap.HeapStats().AllocatedSpace(); | 2288 size_t after_allocation = heap.HeapStats().AllocatedSpace(); |
| 2273 { | 2289 { |
| 2274 object->Set(0, 'a'); | 2290 object->Set(0, 'a'); |
| 2275 EXPECT_EQ('a', object->Get(0)); | 2291 EXPECT_EQ('a', object->Get(0)); |
| 2276 object->Set(object->length() - 1, 'b'); | 2292 object->Set(object->length() - 1, 'b'); |
| 2277 EXPECT_EQ('b', object->Get(object->length() - 1)); | 2293 EXPECT_EQ('b', object->Get(object->length() - 1)); |
| 2278 size_t expected_large_heap_object_payload_size = | 2294 size_t expected_large_heap_object_payload_size = |
| 2279 ThreadHeap::AllocationSizeFromSize(sizeof(LargeHeapObject)); | 2295 ThreadHeap::AllocationSizeFromSize(sizeof(LargeHeapObject)); |
| 2280 size_t expected_object_payload_size = | 2296 size_t expected_object_payload_size = |
| (...skipping 3369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5650 } | 5666 } |
| 5651 #endif | 5667 #endif |
| 5652 #endif | 5668 #endif |
| 5653 | 5669 |
| 5654 static bool AllocateAndReturnBool() { | 5670 static bool AllocateAndReturnBool() { |
| 5655 ConservativelyCollectGarbage(); | 5671 ConservativelyCollectGarbage(); |
| 5656 return true; | 5672 return true; |
| 5657 } | 5673 } |
| 5658 | 5674 |
| 5659 static bool CheckGCForbidden() { | 5675 static bool CheckGCForbidden() { |
| 5660 ASSERT(ThreadState::Current()->IsGCForbidden()); | 5676 DCHECK(ThreadState::Current()->IsGCForbidden()); |
| 5661 return true; | 5677 return true; |
| 5662 } | 5678 } |
| 5663 | 5679 |
| 5664 class MixinClass : public GarbageCollectedMixin { | 5680 class MixinClass : public GarbageCollectedMixin { |
| 5665 public: | 5681 public: |
| 5666 MixinClass() : dummy_(CheckGCForbidden()) {} | 5682 MixinClass() : dummy_(CheckGCForbidden()) {} |
| 5667 | 5683 |
| 5668 private: | 5684 private: |
| 5669 bool dummy_; | 5685 bool dummy_; |
| 5670 }; | 5686 }; |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6204 // Disable ASan, otherwise its stack checking (use-after-return) will | 6220 // Disable ASan, otherwise its stack checking (use-after-return) will |
| 6205 // confuse the direction check. | 6221 // confuse the direction check. |
| 6206 static char* previous = nullptr; | 6222 static char* previous = nullptr; |
| 6207 char dummy; | 6223 char dummy; |
| 6208 if (!previous) { | 6224 if (!previous) { |
| 6209 previous = &dummy; | 6225 previous = &dummy; |
| 6210 GrowthDirection result = StackGrowthDirection(); | 6226 GrowthDirection result = StackGrowthDirection(); |
| 6211 previous = nullptr; | 6227 previous = nullptr; |
| 6212 return result; | 6228 return result; |
| 6213 } | 6229 } |
| 6214 ASSERT(&dummy != previous); | 6230 DCHECK_NE(&dummy, previous); |
| 6215 return &dummy < previous ? kGrowsTowardsLower : kGrowsTowardsHigher; | 6231 return &dummy < previous ? kGrowsTowardsLower : kGrowsTowardsHigher; |
| 6216 } | 6232 } |
| 6217 | 6233 |
| 6218 } // namespace | 6234 } // namespace |
| 6219 | 6235 |
| 6220 TEST(HeapTest, StackGrowthDirection) { | 6236 TEST(HeapTest, StackGrowthDirection) { |
| 6221 // The implementation of marking probes stack usage as it runs, | 6237 // The implementation of marking probes stack usage as it runs, |
| 6222 // and has a builtin assumption that the stack grows towards | 6238 // and has a builtin assumption that the stack grows towards |
| 6223 // lower addresses. | 6239 // lower addresses. |
| 6224 EXPECT_EQ(kGrowsTowardsLower, StackGrowthDirection()); | 6240 EXPECT_EQ(kGrowsTowardsLower, StackGrowthDirection()); |
| 6225 } | 6241 } |
| 6226 | 6242 |
| 6227 class TestMixinAllocationA : public GarbageCollected<TestMixinAllocationA>, | 6243 class TestMixinAllocationA : public GarbageCollected<TestMixinAllocationA>, |
| 6228 public GarbageCollectedMixin { | 6244 public GarbageCollectedMixin { |
| 6229 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationA); | 6245 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationA); |
| 6230 | 6246 |
| 6231 public: | 6247 public: |
| 6232 TestMixinAllocationA() { | 6248 TestMixinAllocationA() { |
| 6233 // Completely wrong in general, but test only | 6249 // Completely wrong in general, but test only |
| 6234 // runs this constructor while constructing another mixin. | 6250 // runs this constructor while constructing another mixin. |
| 6235 ASSERT(ThreadState::Current()->IsGCForbidden()); | 6251 DCHECK(ThreadState::Current()->IsGCForbidden()); |
| 6236 } | 6252 } |
| 6237 | 6253 |
| 6238 DEFINE_INLINE_VIRTUAL_TRACE() {} | 6254 DEFINE_INLINE_VIRTUAL_TRACE() {} |
| 6239 }; | 6255 }; |
| 6240 | 6256 |
| 6241 class TestMixinAllocationB : public TestMixinAllocationA { | 6257 class TestMixinAllocationB : public TestMixinAllocationA { |
| 6242 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationB); | 6258 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationB); |
| 6243 | 6259 |
| 6244 public: | 6260 public: |
| 6245 TestMixinAllocationB() | 6261 TestMixinAllocationB() |
| 6246 : a_(new TestMixinAllocationA()) // Construct object during a mixin | 6262 : a_(new TestMixinAllocationA()) // Construct object during a mixin |
| 6247 // construction. | 6263 // construction. |
| 6248 { | 6264 { |
| 6249 // Completely wrong in general, but test only | 6265 // Completely wrong in general, but test only |
| 6250 // runs this constructor while constructing another mixin. | 6266 // runs this constructor while constructing another mixin. |
| 6251 ASSERT(ThreadState::Current()->IsGCForbidden()); | 6267 DCHECK(ThreadState::Current()->IsGCForbidden()); |
| 6252 } | 6268 } |
| 6253 | 6269 |
| 6254 DEFINE_INLINE_TRACE() { | 6270 DEFINE_INLINE_TRACE() { |
| 6255 visitor->Trace(a_); | 6271 visitor->Trace(a_); |
| 6256 TestMixinAllocationA::Trace(visitor); | 6272 TestMixinAllocationA::Trace(visitor); |
| 6257 } | 6273 } |
| 6258 | 6274 |
| 6259 private: | 6275 private: |
| 6260 Member<TestMixinAllocationA> a_; | 6276 Member<TestMixinAllocationA> a_; |
| 6261 }; | 6277 }; |
| 6262 | 6278 |
| 6263 class TestMixinAllocationC final : public TestMixinAllocationB { | 6279 class TestMixinAllocationC final : public TestMixinAllocationB { |
| 6264 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationC); | 6280 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationC); |
| 6265 | 6281 |
| 6266 public: | 6282 public: |
| 6267 TestMixinAllocationC() { ASSERT(!ThreadState::Current()->IsGCForbidden()); } | 6283 TestMixinAllocationC() { DCHECK(!ThreadState::Current()->IsGCForbidden()); } |
| 6268 | 6284 |
| 6269 DEFINE_INLINE_TRACE() { TestMixinAllocationB::Trace(visitor); } | 6285 DEFINE_INLINE_TRACE() { TestMixinAllocationB::Trace(visitor); } |
| 6270 }; | 6286 }; |
| 6271 | 6287 |
| 6272 TEST(HeapTest, NestedMixinConstruction) { | 6288 TEST(HeapTest, NestedMixinConstruction) { |
| 6273 TestMixinAllocationC* object = new TestMixinAllocationC(); | 6289 TestMixinAllocationC* object = new TestMixinAllocationC(); |
| 6274 EXPECT_TRUE(object); | 6290 EXPECT_TRUE(object); |
| 6275 } | 6291 } |
| 6276 | 6292 |
| 6277 class ObjectWithLargeAmountsOfAllocationInConstructor { | 6293 class ObjectWithLargeAmountsOfAllocationInConstructor { |
| 6278 public: | 6294 public: |
| 6279 ObjectWithLargeAmountsOfAllocationInConstructor( | 6295 ObjectWithLargeAmountsOfAllocationInConstructor( |
| 6280 size_t number_of_large_objects_to_allocate, | 6296 size_t number_of_large_objects_to_allocate, |
| 6281 ClassWithMember* member) { | 6297 ClassWithMember* member) { |
| 6282 // Should a constructor allocate plenty in its constructor, | 6298 // Should a constructor allocate plenty in its constructor, |
| 6283 // and it is a base of GC mixin, GCs will remain locked out | 6299 // and it is a base of GC mixin, GCs will remain locked out |
| 6284 // regardless, as we cannot safely trace the leftmost GC | 6300 // regardless, as we cannot safely trace the leftmost GC |
| 6285 // mixin base. | 6301 // mixin base. |
| 6286 ASSERT(ThreadState::Current()->IsGCForbidden()); | 6302 DCHECK(ThreadState::Current()->IsGCForbidden()); |
| 6287 for (size_t i = 0; i < number_of_large_objects_to_allocate; i++) { | 6303 for (size_t i = 0; i < number_of_large_objects_to_allocate; i++) { |
| 6288 LargeHeapObject* large_object = LargeHeapObject::Create(); | 6304 LargeHeapObject* large_object = LargeHeapObject::Create(); |
| 6289 EXPECT_TRUE(large_object); | 6305 EXPECT_TRUE(large_object); |
| 6290 EXPECT_EQ(0, member->TraceCount()); | 6306 EXPECT_EQ(0, member->TraceCount()); |
| 6291 } | 6307 } |
| 6292 } | 6308 } |
| 6293 }; | 6309 }; |
| 6294 | 6310 |
| 6295 class TestMixinAllocatingObject final | 6311 class TestMixinAllocatingObject final |
| 6296 : public TestMixinAllocationB, | 6312 : public TestMixinAllocationB, |
| 6297 public ObjectWithLargeAmountsOfAllocationInConstructor { | 6313 public ObjectWithLargeAmountsOfAllocationInConstructor { |
| 6298 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocatingObject); | 6314 USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocatingObject); |
| 6299 | 6315 |
| 6300 public: | 6316 public: |
| 6301 static TestMixinAllocatingObject* Create(ClassWithMember* member) { | 6317 static TestMixinAllocatingObject* Create(ClassWithMember* member) { |
| 6302 return new TestMixinAllocatingObject(member); | 6318 return new TestMixinAllocatingObject(member); |
| 6303 } | 6319 } |
| 6304 | 6320 |
| 6305 DEFINE_INLINE_TRACE() { | 6321 DEFINE_INLINE_TRACE() { |
| 6306 visitor->Trace(trace_counter_); | 6322 visitor->Trace(trace_counter_); |
| 6307 TestMixinAllocationB::Trace(visitor); | 6323 TestMixinAllocationB::Trace(visitor); |
| 6308 } | 6324 } |
| 6309 | 6325 |
| 6310 int TraceCount() const { return trace_counter_->TraceCount(); } | 6326 int TraceCount() const { return trace_counter_->TraceCount(); } |
| 6311 | 6327 |
| 6312 private: | 6328 private: |
| 6313 TestMixinAllocatingObject(ClassWithMember* member) | 6329 TestMixinAllocatingObject(ClassWithMember* member) |
| 6314 : ObjectWithLargeAmountsOfAllocationInConstructor(600, member), | 6330 : ObjectWithLargeAmountsOfAllocationInConstructor(600, member), |
| 6315 trace_counter_(TraceCounter::Create()) { | 6331 trace_counter_(TraceCounter::Create()) { |
| 6316 ASSERT(!ThreadState::Current()->IsGCForbidden()); | 6332 DCHECK(!ThreadState::Current()->IsGCForbidden()); |
| 6317 ConservativelyCollectGarbage(); | 6333 ConservativelyCollectGarbage(); |
| 6318 EXPECT_GT(member->TraceCount(), 0); | 6334 EXPECT_GT(member->TraceCount(), 0); |
| 6319 EXPECT_GT(TraceCount(), 0); | 6335 EXPECT_GT(TraceCount(), 0); |
| 6320 } | 6336 } |
| 6321 | 6337 |
| 6322 Member<TraceCounter> trace_counter_; | 6338 Member<TraceCounter> trace_counter_; |
| 6323 }; | 6339 }; |
| 6324 | 6340 |
| 6325 TEST(HeapTest, MixinConstructionNoGC) { | 6341 TEST(HeapTest, MixinConstructionNoGC) { |
| 6326 Persistent<ClassWithMember> object = ClassWithMember::Create(); | 6342 Persistent<ClassWithMember> object = ClassWithMember::Create(); |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6682 map.insert(key, IntWrapper::Create(i)); | 6698 map.insert(key, IntWrapper::Create(i)); |
| 6683 } | 6699 } |
| 6684 | 6700 |
| 6685 EXPECT_FALSE(string.Impl()->HasOneRef()); | 6701 EXPECT_FALSE(string.Impl()->HasOneRef()); |
| 6686 map.Clear(); | 6702 map.Clear(); |
| 6687 | 6703 |
| 6688 EXPECT_TRUE(string.Impl()->HasOneRef()); | 6704 EXPECT_TRUE(string.Impl()->HasOneRef()); |
| 6689 } | 6705 } |
| 6690 | 6706 |
| 6691 } // namespace blink | 6707 } // namespace blink |
| OLD | NEW |