⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 267304 in webkit


Ignore:
Timestamp:
Sep 18, 2020, 6:22:42 PM (6 years ago)
Author:
ysuzuki@apple.com
Message:

[JSC] PreciseAllocation's isNewlyAllocated flag should be propagated from isMarked at GC begin phase to make isLive correct
https://bugs.webkit.org/show_bug.cgi?id=216717

Reviewed by Mark Lam.

When starting full GC, at beginMarking, PreciseAllocation's mark bit is cleared to be usable for upcoming marking.
However, this means that HeapCell::isLive will see this object as dead until it is marked.
Let's consider that this object is not newly allocated one. Then, its isNewlyAllocated is false. And now mark bit

is also cleared. Since PreciseAllocation::isLive is isNewlyAllocated
isMarked, then it looks dead, while it is live.

This confuses HeapCell:isLive function and makes some of watchpoints perform wrong decisions (e.g. this condition is
no longer valid, let's just discard it).
At the beginning of full collection, we should propagate the old mark bit to isNewlyAllocated so that it looks live
during marking. This is similar trick to MarkedBlock::aboutToMark.

  • heap/PreciseAllocation.cpp:

(JSC::PreciseAllocation::flip):

Location:
trunk/Source/JavaScriptCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r267301 r267304  
     12020-09-18  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] PreciseAllocation's isNewlyAllocated flag should be propagated from isMarked at GC begin phase to make isLive correct
     4        https://bugs.webkit.org/show_bug.cgi?id=216717
     5
     6        Reviewed by Mark Lam.
     7
     8        When starting full GC, at beginMarking, PreciseAllocation's mark bit is cleared to be usable for upcoming marking.
     9        However, this means that HeapCell::isLive will see this object as dead until it is marked.
     10        Let's consider that this object is not newly allocated one. Then, its isNewlyAllocated is false. And now mark bit
     11        is also cleared. Since PreciseAllocation::isLive is isNewlyAllocated || isMarked, then it looks dead, while it is live.
     12        This confuses HeapCell:isLive function and makes some of watchpoints perform wrong decisions (e.g. this condition is
     13        no longer valid, let's just discard it).
     14        At the beginning of full collection, we should propagate the old mark bit to isNewlyAllocated so that it looks live
     15        during marking. This is similar trick to MarkedBlock::aboutToMark.
     16
     17        * heap/PreciseAllocation.cpp:
     18        (JSC::PreciseAllocation::flip):
     19
    1202020-09-18  Saam Barati  <sbarati@apple.com>
    221
  • trunk/Source/JavaScriptCore/heap/PreciseAllocation.cpp

    r262570 r267304  
    214214{
    215215    ASSERT(heap()->collectionScope() == CollectionScope::Full);
    216     clearMarked();
     216    // Propagate the last time's mark bit to m_isNewlyAllocated so that `isLive` will say "yes" until this GC cycle finishes.
     217    // After that, m_isNewlyAllocated is cleared again. So only previously marked or actually newly created objects survive.
     218    // We do not need to care about concurrency here since marking thread is stopped right now. This is equivalent to the logic
     219    // of MarkedBlock::aboutToMarkSlow.
     220    // We invoke this function only when this is full collection. This ensures that at the end of upcoming cycle, we will
     221    // clear NewlyAllocated bits of all objects. So this works correctly.
     222    //
     223    //                                      N: NewlyAllocated, M: Marked
     224    //                                                 after this         at the end        When cycle
     225    //                                            N M  function    N M     of cycle    N M  is finished   N M
     226    // The live object survives the last cycle    0 1      =>      1 0        =>       1 1       =>       0 1    => live
     227    // The dead object in the last cycle          0 0      =>      0 0        =>       0 0       =>       0 0    => dead
     228    // The live object newly created after this            =>      1 0        =>       1 1       =>       0 1    => live
     229    // The dead object newly created after this            =>      1 0        =>       1 0       =>       0 0    => dead
     230    // The live object newly created before this  1 0      =>      1 0        =>       1 1       =>       0 1    => live
     231    // The dead object newly created before this  1 0      =>      1 0        =>       1 0       =>       0 0    => dead
     232    //                                                                                                    ^
     233    //                                                              This is ensured since this function is used only for full GC.
     234    m_isNewlyAllocated |= isMarked();
     235    m_isMarked.store(false, std::memory_order_relaxed);
    217236}
    218237
Note: See TracChangeset for help on using the changeset viewer.