Changeset 206183 in webkit


Ignore:
Timestamp:
Sep 20, 2016 3:57:16 PM (8 years ago)
Author:
fpizlo@apple.com
Message:

DFG::StoreBarrierInsertionPhase should assume that any epoch increment may make objects older
https://bugs.webkit.org/show_bug.cgi?id=162319

Reviewed by Saam Barati.

The store barrier phase needs to be aware of the fact that an object that is not in the
OldBlack state may be concurrently brought into that state. That means that:

  • We cannot reason about the relative ages of objects. An object is either new, in which case we can store to it without barriers, or it's not in which case it needs a barrier.


  • After we insert a barrier on an object, the object is no longer new, because now the GC knows about it and the GC may do things to it, like make it OldBlack.


This is a perf-neutral change. These optimizations were never particularly profitable.

  • dfg/DFGStoreBarrierInsertionPhase.cpp:
Location:
trunk/Source/JavaScriptCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r206172 r206183  
     12016-09-20  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG::StoreBarrierInsertionPhase should assume that any epoch increment may make objects older
     4        https://bugs.webkit.org/show_bug.cgi?id=162319
     5
     6        Reviewed by Saam Barati.
     7       
     8        The store barrier phase needs to be aware of the fact that an object that is not in the
     9        OldBlack state may be concurrently brought into that state. That means that:
     10       
     11        - We cannot reason about the relative ages of objects. An object is either new, in which
     12          case we can store to it without barriers, or it's not in which case it needs a barrier.
     13       
     14        - After we insert a barrier on an object, the object is no longer new, because now the GC
     15          knows about it and the GC may do things to it, like make it OldBlack.
     16       
     17        This is a perf-neutral change. These optimizations were never particularly profitable.
     18
     19        * dfg/DFGStoreBarrierInsertionPhase.cpp:
     20
    1212016-09-20  Filip Pizlo  <fpizlo@apple.com>
    222
  • trunk/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp

    r202955 r206183  
    411411        } }
    412412       
    413         // We don't need a store barrier if the base is at least as new as the child. For
    414         // example this won't need a barrier:
    415         //
    416         // var o = {}
    417         // var p = {}
    418         // p.f = o
    419         //
    420         // This is stronger than the currentEpoch rule in considerBarrier(Edge), because it will
    421         // also eliminate barriers in cases like this:
    422         //
    423         // var o = {} // o.epoch = 1, currentEpoch = 1
    424         // var p = {} // o.epoch = 1, p.epoch = 2, currentEpoch = 2
    425         // var q = {} // o.epoch = 1, p.epoch = 2, q.epoch = 3, currentEpoch = 3
    426         // p.f = o // p.epoch >= o.epoch
    427         //
    428         // This relationship works because if it holds then we are in one of the following
    429         // scenarios. Note that we don't know *which* of these scenarios we are in, but it's
    430         // one of them (though without loss of generality, you can replace "a GC happened" with
    431         // "many GCs happened").
    432         //
    433         // 1) There is no GC between the allocation/last-barrier of base, child and now. Then
    434         //    we definitely don't need a barrier.
    435         //
    436         // 2) There was a GC after child was allocated but before base was allocated. Then we
    437         //    don't need a barrier, because base is still a new object.
    438         //
    439         // 3) There was a GC after both child and base were allocated. Then they are both old.
    440         //    We don't need barriers on stores of old into old. Note that in this case it
    441         //    doesn't matter if there was also a GC between the allocation of child and base.
    442         //
    443         // Note that barriers will lift an object into the current epoch. This is sort of weird.
    444         // It means that later if you store that object into some other object, and that other
    445         // object was previously newer object, you'll think that you need a barrier. We could
    446         // avoid this by tracking allocation epoch and barrier epoch separately. For now I think
    447         // that this would be overkill. But this does mean that there are the following
    448         // possibilities when this relationship holds:
    449         //
    450         // 4) Base is allocated first. A GC happens and base becomes old. Then we allocate
    451         //    child. (Note that alternatively the GC could happen during the allocation of
    452         //    child.) Then we run a barrier on base. Base will appear to be as new as child
    453         //    (same epoch). At this point, we don't need another barrier on base.
    454         //
    455         // 5) Base is allocated first. Then we allocate child. Then we run a GC. Then we run a
    456         //    barrier on base. Base will appear newer than child. We don't need a barrier
    457         //    because both objects are old.
    458         //
    459         // Something we watch out for here is that the null epoch is a catch-all for objects
    460         // allocated before we did any epoch tracking. Two objects being in the null epoch
    461         // means that we don't know their epoch relationship.
    462         if (!!base->epoch() && !!child->epoch() && base->epoch() >= child->epoch()) {
    463             if (verbose)
    464                 dataLog("            Rejecting because of epoch ordering.\n");
    465             return;
    466         }
    467 
    468413        considerBarrier(base);
    469414    }
     
    491436    void insertBarrier(unsigned nodeIndex, Edge base, bool exitOK = true)
    492437    {
     438        // Inserting a barrier means that the object may become marked by the GC, which will make
     439        // the object black.
     440        base->setEpoch(Epoch());
     441
    493442        // If we're in global mode, we should only insert the barriers once we have converged.
    494443        if (!reallyInsertBarriers())
     
    509458        m_insertionSet.insertNode(
    510459            nodeIndex, SpecNone, StoreBarrier, m_node->origin.takeValidExit(exitOK), base);
    511 
    512         base->setEpoch(m_currentEpoch);
    513460    }
    514461   
Note: See TracChangeset for help on using the changeset viewer.