Chromium Code Reviews| Index: runtime/vm/dart_api_impl_test.cc |
| diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc |
| index 5498bd704c213ca5deaa1bb6ce6600931f6480f8..d9de3911148ff0521b215b8b7e255a808368f397 100644 |
| --- a/runtime/vm/dart_api_impl_test.cc |
| +++ b/runtime/vm/dart_api_impl_test.cc |
| @@ -1207,6 +1207,28 @@ TEST_CASE(MalformedStringToUTF8) { |
| } |
| +// Helper class to ensure new gen GC is triggered without any side effects. |
| +// The normal call to CollectGarbage(Heap::kNew) could potentially trigger |
| +// an old gen collection if there is a promotion failure and this could |
| +// perturb the test. |
| +class GCTestHelper : public AllStatic { |
| + public: |
| + static void CollectNewSpace(Heap::ApiCallbacks api_callbacks) { |
| + bool invoke_api_callbacks = (api_callbacks == Heap::kInvokeApiCallbacks); |
| + Isolate::Current()->heap()->new_space()->Scavenge(invoke_api_callbacks); |
| + } |
| + |
| + static void WaitForFinalizationTasks() { |
| + Thread* thread = Thread::Current(); |
| + Heap* heap = thread->isolate()->heap(); |
| + MonitorLocker ml(heap->finalization_tasks_lock()); |
| + while (heap->finalization_tasks() > 0) { |
| + ml.WaitWithSafepointCheck(thread); |
| + } |
| + } |
| +}; |
| + |
| + |
| static void ExternalStringCallbackFinalizer(void* peer) { |
| *static_cast<int*>(peer) *= 2; |
| } |
| @@ -1243,9 +1265,11 @@ TEST_CASE(ExternalStringCallback) { |
| EXPECT_EQ(40, peer8); |
| EXPECT_EQ(41, peer16); |
| Isolate::Current()->heap()->CollectGarbage(Heap::kOld); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT_EQ(40, peer8); |
| EXPECT_EQ(41, peer16); |
| Isolate::Current()->heap()->CollectGarbage(Heap::kNew); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT_EQ(80, peer8); |
| EXPECT_EQ(82, peer16); |
| } |
| @@ -2382,13 +2406,74 @@ TEST_CASE(ExternalTypedDataCallback) { |
| TransitionNativeToVM transition(thread); |
| EXPECT(peer == 0); |
| Isolate::Current()->heap()->CollectGarbage(Heap::kOld); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT(peer == 0); |
| Isolate::Current()->heap()->CollectGarbage(Heap::kNew); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT(peer == 42); |
| } |
| } |
| +static Monitor* slow_finalizers_monitor = NULL; |
| +static volatile intptr_t slow_finalizers_waiting = 0; |
| +static volatile intptr_t slow_finalizers_done = 0; |
| + |
| + |
| +static void SlowFinalizer(void* isolate_callback_data, |
| + Dart_WeakPersistentHandle handle, |
| + void* peer) { |
| + { |
| + MonitorLocker ml(slow_finalizers_monitor); |
| + slow_finalizers_waiting++; |
| + while (slow_finalizers_waiting < 10) { |
| + OS::Print("wait"); |
| + ml.Wait(); |
| + } |
|
siva
2016/06/22 22:55:31
See comment below:
Isn't it sufficient to do
whil
rmacnak
2016/06/22 23:13:48
Yes, that works too.
|
| + slow_finalizers_done++; |
| + } |
| + |
| + intptr_t* count = reinterpret_cast<intptr_t*>(peer); |
| + AtomicOperations::IncrementBy(count, 1); |
| +} |
| + |
| + |
| +TEST_CASE(SlowFinalizer) { |
| + slow_finalizers_monitor = new Monitor(); |
| + |
| + intptr_t count = 0; |
| + for (intptr_t i = 0; i < 10; i++) { |
| + Dart_EnterScope(); |
| + Dart_Handle str1 = Dart_NewStringFromCString("Live fast"); |
| + Dart_NewWeakPersistentHandle(str1, &count, 0, SlowFinalizer); |
| + Dart_Handle str2 = Dart_NewStringFromCString("Die young"); |
| + Dart_NewWeakPersistentHandle(str2, &count, 0, SlowFinalizer); |
| + Dart_ExitScope(); |
| + |
| + { |
| + TransitionNativeToVM transition(thread); |
| + Isolate::Current()->heap()->CollectAllGarbage(); |
| + } |
| + } |
| + |
| + { |
| + while (slow_finalizers_done < 20) { |
| + MonitorLocker ml(slow_finalizers_monitor); |
| + ml.NotifyAll(); |
| + } |
| + } |
|
siva
2016/06/22 22:55:31
Why is this block needed here? Isn't it sufficient
|
| + |
| + { |
| + TransitionNativeToVM transition(thread); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| + } |
| + |
| + EXPECT_EQ(20, count); |
| + |
| + delete slow_finalizers_monitor; |
| +} |
| + |
| + |
| static void CheckFloat32x4Data(Dart_Handle obj) { |
| void* raw_data = NULL; |
| intptr_t len; |
| @@ -2440,6 +2525,7 @@ TEST_CASE(Float32x4List) { |
| { |
| TransitionNativeToVM transition(thread); |
| Isolate::Current()->heap()->CollectGarbage(Heap::kNew); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT(peer == 42); |
| } |
| } |
| @@ -2602,19 +2688,6 @@ UNIT_TEST_CASE(AssignToPersistentHandle) { |
| } |
| -// Helper class to ensure new gen GC is triggered without any side effects. |
| -// The normal call to CollectGarbage(Heap::kNew) could potentially trigger |
| -// an old gen collection if there is a promotion failure and this could |
| -// perturb the test. |
| -class GCTestHelper : public AllStatic { |
| - public: |
| - static void CollectNewSpace(Heap::ApiCallbacks api_callbacks) { |
| - bool invoke_api_callbacks = (api_callbacks == Heap::kInvokeApiCallbacks); |
| - Isolate::Current()->heap()->new_space()->Scavenge(invoke_api_callbacks); |
| - } |
| -}; |
| - |
| - |
| static Dart_Handle AsHandle(Dart_PersistentHandle weak) { |
| return Dart_HandleFromPersistent(weak); |
| } |
| @@ -2729,6 +2802,7 @@ TEST_CASE(WeakPersistentHandle) { |
| TransitionNativeToVM transition(thread); |
| // Garbage collect new space again. |
| GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| } |
| { |
| @@ -2744,6 +2818,7 @@ TEST_CASE(WeakPersistentHandle) { |
| TransitionNativeToVM transition(thread); |
| // Garbage collect old space again. |
| Isolate::Current()->heap()->CollectGarbage(Heap::kOld); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| } |
| { |
| @@ -2788,6 +2863,7 @@ TEST_CASE(WeakPersistentHandleCallback) { |
| Isolate::Current()->heap()->CollectGarbage(Heap::kOld); |
| EXPECT(peer == 0); |
| GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT(peer == 42); |
| } |
| } |
| @@ -2814,6 +2890,7 @@ TEST_CASE(WeakPersistentHandleNoCallback) { |
| Isolate::Current()->heap()->CollectGarbage(Heap::kOld); |
| EXPECT(peer == 0); |
| GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT(peer == 0); |
| } |
| } |
| @@ -2874,6 +2951,7 @@ TEST_CASE(WeakPersistentHandleExternalAllocationSize) { |
| // Collect weakly referenced string, and promote strongly referenced string. |
| GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks); |
| GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT(heap->ExternalInWords(Heap::kNew) == 0); |
| EXPECT(heap->ExternalInWords(Heap::kOld) == kWeak2ExternalSize / kWordSize); |
| } |
| @@ -2884,6 +2962,7 @@ TEST_CASE(WeakPersistentHandleExternalAllocationSize) { |
| { |
| TransitionNativeToVM transition(thread); |
| Isolate::Current()->heap()->CollectGarbage(Heap::kOld); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT(heap->ExternalInWords(Heap::kOld) == 0); |
| } |
| } |
| @@ -2929,6 +3008,7 @@ TEST_CASE(WeakPersistentHandleExternalAllocationSizeNewspaceGC) { |
| { |
| TransitionNativeToVM transition(thread); |
| Isolate::Current()->heap()->CollectGarbage(Heap::kOld); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| EXPECT(heap->ExternalInWords(Heap::kOld) == 0); |
| } |
| } |
| @@ -8707,6 +8787,7 @@ TEST_CASE(MakeExternalString) { |
| { |
| TransitionNativeToVM transition(thread); |
| Isolate::Current()->heap()->CollectAllGarbage(); |
| + GCTestHelper::WaitForFinalizationTasks(); |
| } |
| EXPECT_EQ(80, peer8); |
| EXPECT_EQ(82, peer16); |