Chromium Code Reviews| 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 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 510 // TODO(Oilpan): Avoid calling weak callbacks for dead objects. | 510 // TODO(Oilpan): Avoid calling weak callbacks for dead objects. |
| 511 // We can do that by checking isHeapObjectAlive(object) before | 511 // We can do that by checking isHeapObjectAlive(object) before |
| 512 // calling the weak callback, but in that case Callback::Item | 512 // calling the weak callback, but in that case Callback::Item |
| 513 // needs to understand T*. | 513 // needs to understand T*. |
| 514 item->call(visitor); | 514 item->call(visitor); |
| 515 return true; | 515 return true; |
| 516 } | 516 } |
| 517 return false; | 517 return false; |
| 518 } | 518 } |
| 519 | 519 |
| 520 void ThreadState::threadLocalWeakProcessing() | |
| 521 { | |
| 522 ASSERT(!sweepForbidden()); | |
| 523 TRACE_EVENT0("blink_gc", "ThreadState::threadLocalWeakProcessing"); | |
| 524 SweepForbiddenScope forbiddenScope(this); | |
| 525 if (isMainThread()) | |
| 526 ScriptForbiddenScope::enter(); | |
| 527 | |
| 528 // Disallow allocation during weak processing. | |
| 529 // It would be technically safe to allow allocations, but it is unsafe | |
| 530 // to mutate an object graph in a way in which a dead object gets | |
| 531 // resurrected or mutate a HashTable (because HashTable's weak processing | |
| 532 // assumes that the HashTable hasn't been mutated since the latest marking). | |
| 533 // Due to the complexity, we just forbid allocations. | |
| 534 NoAllocationScope noAllocationScope(this); | |
| 535 | |
| 536 MarkingVisitor<Visitor::WeakProcessing> weakProcessingVisitor; | |
| 537 | |
| 538 // Perform thread-specific weak processing. | |
| 539 while (popAndInvokeThreadLocalWeakCallback(&weakProcessingVisitor)) { } | |
| 540 | |
| 541 if (isMainThread()) | |
| 542 ScriptForbiddenScope::exit(); | |
| 543 } | |
| 544 | |
| 520 PersistentAnchor& ThreadState::globalRoots() | 545 PersistentAnchor& ThreadState::globalRoots() |
| 521 { | 546 { |
| 522 AtomicallyInitializedStaticReference(PersistentAnchor, anchor, new Persisten tAnchor); | 547 AtomicallyInitializedStaticReference(PersistentAnchor, anchor, new Persisten tAnchor); |
| 523 return anchor; | 548 return anchor; |
| 524 } | 549 } |
| 525 | 550 |
| 526 Mutex& ThreadState::globalRootsMutex() | 551 Mutex& ThreadState::globalRootsMutex() |
| 527 { | 552 { |
| 528 AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex); | 553 AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex); |
| 529 return mutex; | 554 return mutex; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 672 if (!isSweepingInProgress()) | 697 if (!isSweepingInProgress()) |
| 673 return; | 698 return; |
| 674 | 699 |
| 675 // This check is here to prevent performIdleLazySweep() from being called | 700 // This check is here to prevent performIdleLazySweep() from being called |
| 676 // recursively. I'm not sure if it can happen but it would be safer to have | 701 // recursively. I'm not sure if it can happen but it would be safer to have |
| 677 // the check just in case. | 702 // the check just in case. |
| 678 if (sweepForbidden()) | 703 if (sweepForbidden()) |
| 679 return; | 704 return; |
| 680 | 705 |
| 681 bool sweepCompleted = true; | 706 bool sweepCompleted = true; |
| 682 ThreadState::SweepForbiddenScope scope(this); | 707 SweepForbiddenScope scope(this); |
| 683 { | 708 { |
| 684 if (isMainThread()) | 709 if (isMainThread()) |
| 685 ScriptForbiddenScope::enter(); | 710 ScriptForbiddenScope::enter(); |
| 686 | 711 |
| 687 for (int i = 0; i < NumberOfHeaps; i++) { | 712 for (int i = 0; i < NumberOfHeaps; i++) { |
| 688 // lazySweepWithDeadline() won't check the deadline until it sweeps | 713 // lazySweepWithDeadline() won't check the deadline until it sweeps |
| 689 // 10 pages. So we give a small slack for safety. | 714 // 10 pages. So we give a small slack for safety. |
| 690 double slack = 0.001; | 715 double slack = 0.001; |
| 691 double remainingBudget = deadlineSeconds - slack - Platform::current ()->monotonicallyIncreasingTime(); | 716 double remainingBudget = deadlineSeconds - slack - Platform::current ()->monotonicallyIncreasingTime(); |
| 692 if (remainingBudget <= 0 || !m_heaps[i]->lazySweepWithDeadline(deadl ineSeconds)) { | 717 if (remainingBudget <= 0 || !m_heaps[i]->lazySweepWithDeadline(deadl ineSeconds)) { |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 943 m_gcState = NoGCScheduled; | 968 m_gcState = NoGCScheduled; |
| 944 } | 969 } |
| 945 } | 970 } |
| 946 | 971 |
| 947 void ThreadState::preSweep() | 972 void ThreadState::preSweep() |
| 948 { | 973 { |
| 949 checkThread(); | 974 checkThread(); |
| 950 if (gcState() != EagerSweepScheduled && gcState() != LazySweepScheduled) | 975 if (gcState() != EagerSweepScheduled && gcState() != LazySweepScheduled) |
| 951 return; | 976 return; |
| 952 | 977 |
| 953 { | 978 threadLocalWeakProcessing(); |
| 954 if (isMainThread()) | |
| 955 ScriptForbiddenScope::enter(); | |
| 956 | 979 |
| 957 SweepForbiddenScope forbiddenScope(this); | 980 GCState previousGCState = gcState(); |
|
sof
2015/06/18 12:18:03
This runs the risk of triggering an unused variabl
haraken
2015/06/18 16:30:13
Done.
| |
| 958 { | 981 setGCState(Sweeping); |
|
sof
2015/06/18 12:18:03
Moving this up before running the prefinalizers ma
haraken
2015/06/18 16:30:13
Moving setGCState(Sweeping) up here is necessary t
| |
| 959 MarkingVisitor<Visitor::WeakProcessing> weakProcessingVisitor; | |
| 960 | 982 |
| 961 // Disallow allocation during weak processing. | 983 // Allocation is allowed during the pre-finalizers and destructors. |
| 962 NoAllocationScope noAllocationScope(this); | 984 // However, they must not mutate an object graph in a way in which |
| 963 { | 985 // a dead object gets resurrected. |
| 964 // Perform thread-specific weak processing. | 986 invokePreFinalizers(); |
| 965 TRACE_EVENT0("blink_gc", "ThreadState::threadLocalWeakProcessing "); | |
| 966 while (popAndInvokeThreadLocalWeakCallback(&weakProcessingVisito r)) { } | |
| 967 } | |
| 968 { | |
| 969 TRACE_EVENT0("blink_gc", "ThreadState::invokePreFinalizers"); | |
| 970 invokePreFinalizers(); | |
| 971 } | |
| 972 } | |
| 973 | |
| 974 if (isMainThread()) | |
| 975 ScriptForbiddenScope::exit(); | |
| 976 } | |
| 977 | 987 |
| 978 #if defined(ADDRESS_SANITIZER) | 988 #if defined(ADDRESS_SANITIZER) |
| 979 poisonEagerHeap(SetPoison); | 989 poisonEagerHeap(SetPoison); |
| 980 #endif | 990 #endif |
| 981 | 991 |
| 982 #if ENABLE(LAZY_SWEEPING) | 992 #if ENABLE(LAZY_SWEEPING) |
| 983 if (gcState() == EagerSweepScheduled) { | 993 if (previousGCState == EagerSweepScheduled) { |
| 984 // Eager sweeping should happen only in testing. | 994 // Eager sweeping should happen only in testing. |
| 985 setGCState(Sweeping); | |
| 986 eagerSweep(); | 995 eagerSweep(); |
| 987 #if defined(ADDRESS_SANITIZER) | 996 #if defined(ADDRESS_SANITIZER) |
| 988 poisonAllHeaps(); | 997 poisonAllHeaps(); |
| 989 #endif | 998 #endif |
| 990 completeSweep(); | 999 completeSweep(); |
| 991 } else { | 1000 } else { |
| 992 // The default behavior is lazy sweeping. | 1001 // The default behavior is lazy sweeping. |
| 993 setGCState(Sweeping); | |
| 994 eagerSweep(); | 1002 eagerSweep(); |
| 995 #if defined(ADDRESS_SANITIZER) | 1003 #if defined(ADDRESS_SANITIZER) |
| 996 poisonAllHeaps(); | 1004 poisonAllHeaps(); |
| 997 #endif | 1005 #endif |
| 998 scheduleIdleLazySweep(); | 1006 scheduleIdleLazySweep(); |
| 999 } | 1007 } |
| 1000 #else | 1008 #else |
| 1001 setGCState(Sweeping); | |
| 1002 completeSweep(); | 1009 completeSweep(); |
| 1003 #endif | 1010 #endif |
| 1004 | 1011 |
| 1005 #if ENABLE(GC_PROFILING) | 1012 #if ENABLE(GC_PROFILING) |
| 1006 snapshotFreeListIfNecessary(); | 1013 snapshotFreeListIfNecessary(); |
| 1007 #endif | 1014 #endif |
| 1008 } | 1015 } |
| 1009 | 1016 |
| 1010 #if defined(ADDRESS_SANITIZER) | 1017 #if defined(ADDRESS_SANITIZER) |
| 1011 void ThreadState::poisonAllHeaps() | 1018 void ThreadState::poisonAllHeaps() |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1033 { | 1040 { |
| 1034 // Some objects need to be finalized promptly and cannot be handled | 1041 // Some objects need to be finalized promptly and cannot be handled |
| 1035 // by lazy sweeping. Keep those in a designated heap and sweep it | 1042 // by lazy sweeping. Keep those in a designated heap and sweep it |
| 1036 // eagerly. | 1043 // eagerly. |
| 1037 ASSERT(isSweepingInProgress()); | 1044 ASSERT(isSweepingInProgress()); |
| 1038 | 1045 |
| 1039 // Mirroring the completeSweep() condition; see its comment. | 1046 // Mirroring the completeSweep() condition; see its comment. |
| 1040 if (sweepForbidden()) | 1047 if (sweepForbidden()) |
| 1041 return; | 1048 return; |
| 1042 | 1049 |
| 1043 ThreadState::SweepForbiddenScope scope(this); | 1050 SweepForbiddenScope scope(this); |
| 1044 { | 1051 { |
| 1045 if (isMainThread()) | 1052 if (isMainThread()) |
| 1046 ScriptForbiddenScope::enter(); | 1053 ScriptForbiddenScope::enter(); |
| 1047 | 1054 |
| 1048 m_heaps[EagerSweepHeapIndex]->completeSweep(); | 1055 m_heaps[EagerSweepHeapIndex]->completeSweep(); |
| 1049 | 1056 |
| 1050 if (isMainThread()) | 1057 if (isMainThread()) |
| 1051 ScriptForbiddenScope::exit(); | 1058 ScriptForbiddenScope::exit(); |
| 1052 } | 1059 } |
| 1053 } | 1060 } |
| 1054 | 1061 |
| 1055 void ThreadState::completeSweep() | 1062 void ThreadState::completeSweep() |
| 1056 { | 1063 { |
| 1057 // If we are not in a sweeping phase, there is nothing to do here. | 1064 // If we are not in a sweeping phase, there is nothing to do here. |
| 1058 if (!isSweepingInProgress()) | 1065 if (!isSweepingInProgress()) |
| 1059 return; | 1066 return; |
| 1060 | 1067 |
| 1061 // completeSweep() can be called recursively if finalizers can allocate | 1068 // completeSweep() can be called recursively if finalizers can allocate |
| 1062 // memory and the allocation triggers completeSweep(). This check prevents | 1069 // memory and the allocation triggers completeSweep(). This check prevents |
| 1063 // the sweeping from being executed recursively. | 1070 // the sweeping from being executed recursively. |
| 1064 if (sweepForbidden()) | 1071 if (sweepForbidden()) |
| 1065 return; | 1072 return; |
| 1066 | 1073 |
| 1067 ThreadState::SweepForbiddenScope scope(this); | 1074 SweepForbiddenScope scope(this); |
| 1068 { | 1075 { |
| 1069 if (isMainThread()) | 1076 if (isMainThread()) |
| 1070 ScriptForbiddenScope::enter(); | 1077 ScriptForbiddenScope::enter(); |
| 1071 | 1078 |
| 1072 TRACE_EVENT0("blink_gc", "ThreadState::completeSweep"); | 1079 TRACE_EVENT0("blink_gc", "ThreadState::completeSweep"); |
| 1073 double timeStamp = WTF::currentTimeMS(); | 1080 double timeStamp = WTF::currentTimeMS(); |
| 1074 | 1081 |
| 1075 static_assert(EagerSweepHeapIndex == 0, "Eagerly swept heaps must be pro cessed first."); | 1082 static_assert(EagerSweepHeapIndex == 0, "Eagerly swept heaps must be pro cessed first."); |
| 1076 for (int i = 0; i < NumberOfHeaps; i++) | 1083 for (int i = 0; i < NumberOfHeaps; i++) |
| 1077 m_heaps[i]->completeSweep(); | 1084 m_heaps[i]->completeSweep(); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1290 if (sweepForbidden()) | 1297 if (sweepForbidden()) |
| 1291 return; | 1298 return; |
| 1292 auto it = m_preFinalizers.find(target); | 1299 auto it = m_preFinalizers.find(target); |
| 1293 ASSERT(it != m_preFinalizers.end()); | 1300 ASSERT(it != m_preFinalizers.end()); |
| 1294 m_preFinalizers.remove(it); | 1301 m_preFinalizers.remove(it); |
| 1295 } | 1302 } |
| 1296 | 1303 |
| 1297 void ThreadState::invokePreFinalizers() | 1304 void ThreadState::invokePreFinalizers() |
| 1298 { | 1305 { |
| 1299 checkThread(); | 1306 checkThread(); |
| 1307 ASSERT(!sweepForbidden()); | |
| 1308 TRACE_EVENT0("blink_gc", "ThreadState::invokePreFinalizers"); | |
| 1309 | |
| 1310 if (isMainThread()) | |
| 1311 ScriptForbiddenScope::enter(); | |
| 1312 | |
| 1313 SweepForbiddenScope forbiddenScope(this); | |
| 1300 Vector<void*> deadObjects; | 1314 Vector<void*> deadObjects; |
| 1301 for (auto& entry : m_preFinalizers) { | 1315 for (auto& entry : m_preFinalizers) { |
| 1302 if (entry.value(entry.key)) | 1316 if (entry.value(entry.key)) |
| 1303 deadObjects.append(entry.key); | 1317 deadObjects.append(entry.key); |
| 1304 } | 1318 } |
| 1305 // FIXME: removeAll is inefficient. It can shrink repeatedly. | 1319 // FIXME: removeAll is inefficient. It can shrink repeatedly. |
| 1306 m_preFinalizers.removeAll(deadObjects); | 1320 m_preFinalizers.removeAll(deadObjects); |
| 1321 | |
| 1322 if (isMainThread()) | |
| 1323 ScriptForbiddenScope::exit(); | |
| 1307 } | 1324 } |
| 1308 | 1325 |
| 1309 void ThreadState::clearHeapAges() | 1326 void ThreadState::clearHeapAges() |
| 1310 { | 1327 { |
| 1311 memset(m_heapAges, 0, sizeof(size_t) * NumberOfHeaps); | 1328 memset(m_heapAges, 0, sizeof(size_t) * NumberOfHeaps); |
| 1312 memset(m_likelyToBePromptlyFreed.get(), 0, sizeof(int) * likelyToBePromptlyF reedArraySize); | 1329 memset(m_likelyToBePromptlyFreed.get(), 0, sizeof(int) * likelyToBePromptlyF reedArraySize); |
| 1313 m_currentHeapAges = 0; | 1330 m_currentHeapAges = 0; |
| 1314 } | 1331 } |
| 1315 | 1332 |
| 1316 int ThreadState::heapIndexOfVectorHeapLeastRecentlyExpanded(int beginHeapIndex, int endHeapIndex) | 1333 int ThreadState::heapIndexOfVectorHeapLeastRecentlyExpanded(int beginHeapIndex, int endHeapIndex) |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1447 json->beginArray(it->key.ascii().data()); | 1464 json->beginArray(it->key.ascii().data()); |
| 1448 for (size_t age = 0; age <= maxHeapObjectAge; ++age) | 1465 for (size_t age = 0; age <= maxHeapObjectAge; ++age) |
| 1449 json->pushInteger(it->value.ages[age]); | 1466 json->pushInteger(it->value.ages[age]); |
| 1450 json->endArray(); | 1467 json->endArray(); |
| 1451 } | 1468 } |
| 1452 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s tatsName, this, json.release()); | 1469 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s tatsName, this, json.release()); |
| 1453 } | 1470 } |
| 1454 #endif | 1471 #endif |
| 1455 | 1472 |
| 1456 } // namespace blink | 1473 } // namespace blink |
| OLD | NEW |