Ignore:
Timestamp:
Feb 10, 2017, 8:05:06 PM (8 years ago)
Author:
[email protected]
Message:

Object allocation sinking phase doesn't properly handle control flow when emitting a PutHint of a materialized object into a PromotedHeapLocation of a still sunken object
https://bugs.webkit.org/show_bug.cgi?id=168140
<rdar://problem/30205880>

Reviewed by Filip Pizlo.

JSTests:

  • stress/allocation-sinking-puthint-control-flow.js: Added.

(e):
(bar):
(let.y):
(else.let.y):
(baz):
(foo):
(catch):

Source/JavaScriptCore:

This patch fixes a bug in allocation sinking phase where
we don't properly handle control flow when materializing
an object and also PutHinting that materialization into
a still sunken object. We were performing the PutHint
for the materialization at the point of materialization,
however, we may have materialized along both edges
of a control flow diamond, in which case, we need to
also PutHint at the join point. Consider this program:

`
bb#0:
b: PhantomActivation()
a: PhantomNewFunction()
c: PutHint(@a, @b, ActivationLoc)
Branch(#1, #2)

bb#1:
d: MaterializeActivation()
e: PutHint(@a, @d, ActivationLoc)
f: Upsilon(@d, p)
Jump(#3)

bb#2:
g: MaterializeActivation()
h: PutHint(@a, @g, ActivationLoc)
i: Upsilon(@d, p)
Jump(#3)

bb#3:
p: Phi()
What is PromotedHeapLocation(@a, ActivationLoc) here?
What would we do if we exited?
`
Before this patch, we didn't perform a PutHint of the Phi.
However, we need to, otherwise when exit, we won't know
the value of PromotedHeapLocation(@a, ActivationLoc)

The program we need then, for correctness, is this:
`
bb#0:
b: PhantomActivation()
a: PhantomNewFunction()
c: PutHint(@a, @b, ActivationLoc)
Branch(#1, #2)

bb#1:
d: MaterializeActivation()
e: PutHint(@a, @d, ActivationLoc)
f: Upsilon(@d, p)
Jump(#3)

bb#2:
g: MaterializeActivation()
h: PutHint(@a, @g, ActivationLoc)
i: Upsilon(@d, p)
Jump(#3)

bb#3:
p: Phi()
j: PutHint(@a, @p, ActivationLoc)
`

This patch makes it so that we emit the necessary PutHint at node j.
I've also added more validation to the OSRAvailabilityAnalysisPhase
to catch this problem during validation.

  • dfg/DFGOSRAvailabilityAnalysisPhase.cpp:

(JSC::DFG::OSRAvailabilityAnalysisPhase::run):

  • dfg/DFGObjectAllocationSinkingPhase.cpp:
  • ftl/FTLOperations.cpp:

(JSC::FTL::operationMaterializeObjectInOSR):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp

    r211237 r212177  
    10881088        m_materializationSiteToMaterializations.clear();
    10891089        m_materializationSiteToRecoveries.clear();
     1090        m_materializationSiteToHints.clear();
    10901091
    10911092        // Logically we wish to consider every allocation and sink
     
    12431244
    12441245        // First collect the hints that will be needed when the node
    1245         // we materialize is still stored into other unescaped sink candidates
    1246         Vector<PromotedHeapLocation> hints;
     1246        // we materialize is still stored into other unescaped sink candidates.
     1247        // The way to interpret this vector is:
     1248        //
     1249        // PromotedHeapLocation(NotEscapedAllocation, field) = identifierAllocation
     1250        //
     1251        // e.g:
     1252        // PromotedHeapLocation(@PhantomNewFunction, FunctionActivationPLoc) = IdentifierOf(@MaterializeCreateActivation)
     1253        // or:
     1254        // PromotedHeapLocation(@PhantomCreateActivation, ClosureVarPLoc(x)) = IdentifierOf(@NewFunction)
     1255        //
     1256        // When the rhs of the `=` is to be materialized at this `where` point in the program
     1257        // and IdentifierOf(Materialization) is the original sunken allocation of the materialization.
     1258        //
     1259        // The reason we need to collect all the `identifiers` here is that
     1260        // we may materialize multiple versions of the allocation along control
     1261        // flow edges. We will PutHint these values along those edges. However,
     1262        // we also need to PutHint them when we join and have a Phi of the allocations.
     1263        Vector<std::pair<PromotedHeapLocation, Node*>> hints;
    12471264        for (const auto& entry : m_heap.allocations()) {
    12481265            if (escapees.contains(entry.key))
     
    12511268            for (const auto& field : entry.value.fields()) {
    12521269                ASSERT(m_sinkCandidates.contains(entry.key) || !escapees.contains(field.value));
    1253                 if (escapees.contains(field.value))
    1254                     hints.append(PromotedHeapLocation(entry.key, field.key));
     1270                auto iter = escapees.find(field.value);
     1271                if (iter != escapees.end()) {
     1272                    ASSERT(m_sinkCandidates.contains(field.value));
     1273                    hints.append(std::make_pair(PromotedHeapLocation(entry.key, field.key), field.value));
     1274                }
    12551275            }
    12561276        }
     
    14311451        // The hints need to be after the "real" recoveries so that we
    14321452        // don't hint not-yet-complete objects
    1433         if (!hints.isEmpty()) {
    1434             m_materializationSiteToRecoveries.add(
    1435                 where, Vector<PromotedHeapLocation>()).iterator->value.appendVector(hints);
    1436         }
     1453        m_materializationSiteToHints.add(
     1454            where, Vector<std::pair<PromotedHeapLocation, Node*>>()).iterator->value.appendVector(hints);
    14371455    }
    14381456
     
    15481566        if (!m_bottom)
    15491567            m_bottom = m_insertionSet.insertConstant(0, m_graph.block(0)->at(0)->origin, jsNumber(1927));
     1568
     1569        Vector<HashSet<PromotedHeapLocation>> hintsForPhi(m_sinkCandidates.size());
     1570
    15501571        for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
    15511572            m_heap = m_heapAtHead[block];
     
    15671588                    Node* escapee = m_materializationToEscapee.get(materialization);
    15681589                    m_allocationSSA.newDef(m_nodeToVariable.get(escapee), block, materialization);
     1590                }
     1591
     1592                for (std::pair<PromotedHeapLocation, Node*> pair : m_materializationSiteToHints.get(node)) {
     1593                    PromotedHeapLocation location = pair.first;
     1594                    Node* identifier = pair.second;
     1595                    // We're materializing `identifier` at this point, and the unmaterialized
     1596                    // version is inside `location`. We track which SSA variable this belongs
     1597                    // to in case we also need a PutHint for the Phi.
     1598                    if (UNLIKELY(validationEnabled())) {
     1599                        RELEASE_ASSERT(m_sinkCandidates.contains(location.base()));
     1600                        RELEASE_ASSERT(m_sinkCandidates.contains(identifier));
     1601
     1602                        bool found = false;
     1603                        for (Node* materialization : m_materializationSiteToMaterializations.get(node)) {
     1604                            // We're materializing `identifier` here. This asserts that this is indeed the case.
     1605                            if (m_materializationToEscapee.get(materialization) == identifier) {
     1606                                found = true;
     1607                                break;
     1608                            }
     1609                        }
     1610                        RELEASE_ASSERT(found);
     1611                    }
     1612
     1613                    SSACalculator::Variable* variable = m_nodeToVariable.get(identifier);
     1614                    hintsForPhi[variable->index()].add(location);
    15691615                }
    15701616
     
    16841730                    0, block->at(0)->origin, canExit,
    16851731                    availabilityCalculator.m_availability, identifier, phiDef->value());
     1732
     1733                for (PromotedHeapLocation location : hintsForPhi[variable->index()]) {
     1734                    m_insertionSet.insert(0,
     1735                        location.createHint(m_graph, block->at(0)->origin.withInvalidExit(), phiDef->value()));
     1736                    m_localMapping.set(location, phiDef->value());
     1737                }
    16861738            }
    16871739
     
    17231775                for (PromotedHeapLocation location : m_materializationSiteToRecoveries.get(node))
    17241776                    m_insertionSet.insert(nodeIndex, createRecovery(block, location, node, canExit));
     1777                for (std::pair<PromotedHeapLocation, Node*> pair : m_materializationSiteToHints.get(node))
     1778                    m_insertionSet.insert(nodeIndex, createRecovery(block, pair.first, node, canExit));
    17251779
    17261780                // We need to put the OSR hints after the recoveries,
     
    22102264    HashMap<Node*, Vector<Node*>> m_materializationSiteToMaterializations;
    22112265    HashMap<Node*, Vector<PromotedHeapLocation>> m_materializationSiteToRecoveries;
     2266    HashMap<Node*, Vector<std::pair<PromotedHeapLocation, Node*>>> m_materializationSiteToHints;
    22122267
    22132268    HashMap<Node*, Vector<PromotedHeapLocation>> m_locationsForAllocation;
Note: See TracChangeset for help on using the changeset viewer.