| 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 #if ENABLE(LAZY_SWEEPING) |
| 958 { | 981 GCState previousGCState = gcState(); |
| 959 MarkingVisitor<Visitor::WeakProcessing> weakProcessingVisitor; | 982 #endif |
| 983 // We have to set the GCState to Sweeping before calling pre-finalizers |
| 984 // to disallow a GC during the pre-finalizers. |
| 985 setGCState(Sweeping); |
| 960 | 986 |
| 961 // Disallow allocation during weak processing. | 987 // Allocation is allowed during the pre-finalizers and destructors. |
| 962 NoAllocationScope noAllocationScope(this); | 988 // However, they must not mutate an object graph in a way in which |
| 963 { | 989 // a dead object gets resurrected. |
| 964 // Perform thread-specific weak processing. | 990 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 | 991 |
| 978 #if defined(ADDRESS_SANITIZER) | 992 #if defined(ADDRESS_SANITIZER) |
| 979 poisonEagerHeap(SetPoison); | 993 poisonEagerHeap(SetPoison); |
| 980 #endif | 994 #endif |
| 981 | 995 |
| 982 #if ENABLE(LAZY_SWEEPING) | 996 #if ENABLE(LAZY_SWEEPING) |
| 983 if (gcState() == EagerSweepScheduled) { | 997 if (previousGCState == EagerSweepScheduled) { |
| 984 // Eager sweeping should happen only in testing. | 998 // Eager sweeping should happen only in testing. |
| 985 setGCState(Sweeping); | |
| 986 eagerSweep(); | 999 eagerSweep(); |
| 987 #if defined(ADDRESS_SANITIZER) | 1000 #if defined(ADDRESS_SANITIZER) |
| 988 poisonAllHeaps(); | 1001 poisonAllHeaps(); |
| 989 #endif | 1002 #endif |
| 990 completeSweep(); | 1003 completeSweep(); |
| 991 } else { | 1004 } else { |
| 992 // The default behavior is lazy sweeping. | 1005 // The default behavior is lazy sweeping. |
| 993 setGCState(Sweeping); | |
| 994 eagerSweep(); | 1006 eagerSweep(); |
| 995 #if defined(ADDRESS_SANITIZER) | 1007 #if defined(ADDRESS_SANITIZER) |
| 996 poisonAllHeaps(); | 1008 poisonAllHeaps(); |
| 997 #endif | 1009 #endif |
| 998 scheduleIdleLazySweep(); | 1010 scheduleIdleLazySweep(); |
| 999 } | 1011 } |
| 1000 #else | 1012 #else |
| 1001 setGCState(Sweeping); | |
| 1002 completeSweep(); | 1013 completeSweep(); |
| 1003 #endif | 1014 #endif |
| 1004 | 1015 |
| 1005 #if ENABLE(GC_PROFILING) | 1016 #if ENABLE(GC_PROFILING) |
| 1006 snapshotFreeListIfNecessary(); | 1017 snapshotFreeListIfNecessary(); |
| 1007 #endif | 1018 #endif |
| 1008 } | 1019 } |
| 1009 | 1020 |
| 1010 #if defined(ADDRESS_SANITIZER) | 1021 #if defined(ADDRESS_SANITIZER) |
| 1011 void ThreadState::poisonAllHeaps() | 1022 void ThreadState::poisonAllHeaps() |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1033 { | 1044 { |
| 1034 // Some objects need to be finalized promptly and cannot be handled | 1045 // Some objects need to be finalized promptly and cannot be handled |
| 1035 // by lazy sweeping. Keep those in a designated heap and sweep it | 1046 // by lazy sweeping. Keep those in a designated heap and sweep it |
| 1036 // eagerly. | 1047 // eagerly. |
| 1037 ASSERT(isSweepingInProgress()); | 1048 ASSERT(isSweepingInProgress()); |
| 1038 | 1049 |
| 1039 // Mirroring the completeSweep() condition; see its comment. | 1050 // Mirroring the completeSweep() condition; see its comment. |
| 1040 if (sweepForbidden()) | 1051 if (sweepForbidden()) |
| 1041 return; | 1052 return; |
| 1042 | 1053 |
| 1043 ThreadState::SweepForbiddenScope scope(this); | 1054 SweepForbiddenScope scope(this); |
| 1044 { | 1055 { |
| 1045 if (isMainThread()) | 1056 if (isMainThread()) |
| 1046 ScriptForbiddenScope::enter(); | 1057 ScriptForbiddenScope::enter(); |
| 1047 | 1058 |
| 1048 m_heaps[EagerSweepHeapIndex]->completeSweep(); | 1059 m_heaps[EagerSweepHeapIndex]->completeSweep(); |
| 1049 | 1060 |
| 1050 if (isMainThread()) | 1061 if (isMainThread()) |
| 1051 ScriptForbiddenScope::exit(); | 1062 ScriptForbiddenScope::exit(); |
| 1052 } | 1063 } |
| 1053 } | 1064 } |
| 1054 | 1065 |
| 1055 void ThreadState::completeSweep() | 1066 void ThreadState::completeSweep() |
| 1056 { | 1067 { |
| 1057 // If we are not in a sweeping phase, there is nothing to do here. | 1068 // If we are not in a sweeping phase, there is nothing to do here. |
| 1058 if (!isSweepingInProgress()) | 1069 if (!isSweepingInProgress()) |
| 1059 return; | 1070 return; |
| 1060 | 1071 |
| 1061 // completeSweep() can be called recursively if finalizers can allocate | 1072 // completeSweep() can be called recursively if finalizers can allocate |
| 1062 // memory and the allocation triggers completeSweep(). This check prevents | 1073 // memory and the allocation triggers completeSweep(). This check prevents |
| 1063 // the sweeping from being executed recursively. | 1074 // the sweeping from being executed recursively. |
| 1064 if (sweepForbidden()) | 1075 if (sweepForbidden()) |
| 1065 return; | 1076 return; |
| 1066 | 1077 |
| 1067 ThreadState::SweepForbiddenScope scope(this); | 1078 SweepForbiddenScope scope(this); |
| 1068 { | 1079 { |
| 1069 if (isMainThread()) | 1080 if (isMainThread()) |
| 1070 ScriptForbiddenScope::enter(); | 1081 ScriptForbiddenScope::enter(); |
| 1071 | 1082 |
| 1072 TRACE_EVENT0("blink_gc", "ThreadState::completeSweep"); | 1083 TRACE_EVENT0("blink_gc", "ThreadState::completeSweep"); |
| 1073 double timeStamp = WTF::currentTimeMS(); | 1084 double timeStamp = WTF::currentTimeMS(); |
| 1074 | 1085 |
| 1075 static_assert(EagerSweepHeapIndex == 0, "Eagerly swept heaps must be pro
cessed first."); | 1086 static_assert(EagerSweepHeapIndex == 0, "Eagerly swept heaps must be pro
cessed first."); |
| 1076 for (int i = 0; i < NumberOfHeaps; i++) | 1087 for (int i = 0; i < NumberOfHeaps; i++) |
| 1077 m_heaps[i]->completeSweep(); | 1088 m_heaps[i]->completeSweep(); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1290 if (sweepForbidden()) | 1301 if (sweepForbidden()) |
| 1291 return; | 1302 return; |
| 1292 auto it = m_preFinalizers.find(target); | 1303 auto it = m_preFinalizers.find(target); |
| 1293 ASSERT(it != m_preFinalizers.end()); | 1304 ASSERT(it != m_preFinalizers.end()); |
| 1294 m_preFinalizers.remove(it); | 1305 m_preFinalizers.remove(it); |
| 1295 } | 1306 } |
| 1296 | 1307 |
| 1297 void ThreadState::invokePreFinalizers() | 1308 void ThreadState::invokePreFinalizers() |
| 1298 { | 1309 { |
| 1299 checkThread(); | 1310 checkThread(); |
| 1311 ASSERT(!sweepForbidden()); |
| 1312 TRACE_EVENT0("blink_gc", "ThreadState::invokePreFinalizers"); |
| 1313 |
| 1314 if (isMainThread()) |
| 1315 ScriptForbiddenScope::enter(); |
| 1316 |
| 1317 SweepForbiddenScope forbiddenScope(this); |
| 1300 Vector<void*> deadObjects; | 1318 Vector<void*> deadObjects; |
| 1301 for (auto& entry : m_preFinalizers) { | 1319 for (auto& entry : m_preFinalizers) { |
| 1302 if (entry.value(entry.key)) | 1320 if (entry.value(entry.key)) |
| 1303 deadObjects.append(entry.key); | 1321 deadObjects.append(entry.key); |
| 1304 } | 1322 } |
| 1305 // FIXME: removeAll is inefficient. It can shrink repeatedly. | 1323 // FIXME: removeAll is inefficient. It can shrink repeatedly. |
| 1306 m_preFinalizers.removeAll(deadObjects); | 1324 m_preFinalizers.removeAll(deadObjects); |
| 1325 |
| 1326 if (isMainThread()) |
| 1327 ScriptForbiddenScope::exit(); |
| 1307 } | 1328 } |
| 1308 | 1329 |
| 1309 void ThreadState::clearHeapAges() | 1330 void ThreadState::clearHeapAges() |
| 1310 { | 1331 { |
| 1311 memset(m_heapAges, 0, sizeof(size_t) * NumberOfHeaps); | 1332 memset(m_heapAges, 0, sizeof(size_t) * NumberOfHeaps); |
| 1312 memset(m_likelyToBePromptlyFreed.get(), 0, sizeof(int) * likelyToBePromptlyF
reedArraySize); | 1333 memset(m_likelyToBePromptlyFreed.get(), 0, sizeof(int) * likelyToBePromptlyF
reedArraySize); |
| 1313 m_currentHeapAges = 0; | 1334 m_currentHeapAges = 0; |
| 1314 } | 1335 } |
| 1315 | 1336 |
| 1316 int ThreadState::heapIndexOfVectorHeapLeastRecentlyExpanded(int beginHeapIndex,
int endHeapIndex) | 1337 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()); | 1468 json->beginArray(it->key.ascii().data()); |
| 1448 for (size_t age = 0; age <= maxHeapObjectAge; ++age) | 1469 for (size_t age = 0; age <= maxHeapObjectAge; ++age) |
| 1449 json->pushInteger(it->value.ages[age]); | 1470 json->pushInteger(it->value.ages[age]); |
| 1450 json->endArray(); | 1471 json->endArray(); |
| 1451 } | 1472 } |
| 1452 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); | 1473 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); |
| 1453 } | 1474 } |
| 1454 #endif | 1475 #endif |
| 1455 | 1476 |
| 1456 } // namespace blink | 1477 } // namespace blink |
| OLD | NEW |