WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch
bug-143073-20150504141608.patch (text/plain), 45.60 KB, created by
Basile Clement
on 2015-05-04 14:17:22 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Basile Clement
Created:
2015-05-04 14:17:22 PDT
Size:
45.60 KB
patch
obsolete
>Subversion Revision: 183493 >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index a8c0796b53d97c4c3d1a43179237b525aa7ea27d..c095631e08f8434ee5e0b46e92a6626a4d180b8b 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -1364,6 +1364,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > > case PhantomNewObject: >+ case PopulateNewObject: > case PhantomNewFunction: > case PhantomDirectArguments: > case PhantomClonedArguments: >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index d38579e34bb8064327196ec250c69311141f1c03..bbd4e5aa518bfce2f8ec24430925fb78c970b980 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -857,6 +857,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case NewStringObject: > case PhantomNewObject: > case MaterializeNewObject: >+ case PopulateNewObject: > case PhantomNewFunction: > read(HeapObjectCount); > write(HeapObjectCount); >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index 4871f0a96231d173ed90162750f094c7e1b115b2..f3fc6abbba39508ced0bc87dab7120f35ebc35ab 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -197,6 +197,7 @@ bool doesGC(Graph& graph, Node* node) > case CheckBadCell: > case BottomValue: > case PhantomNewObject: >+ case PopulateNewObject: > case PhantomNewFunction: > case PhantomDirectArguments: > case PhantomClonedArguments: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index f74ecbdf44b9d173334c32c07f901db2d4d1ae30..5afe8013e25931fcf9f7f5486cb46fab78c5fa7d 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -1048,6 +1048,7 @@ private: > case PutHint: > case CheckStructureImmediate: > case MaterializeNewObject: >+ case PopulateNewObject: > case PutStack: > case KillStack: > case GetStack: >diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h >index 656fd5fa30fcc9bc19ebeb1ee9e7c5c187874545..59e962550dd984d507e4f36b4bd534f0067f0e8f 100644 >--- a/Source/JavaScriptCore/dfg/DFGNode.h >+++ b/Source/JavaScriptCore/dfg/DFGNode.h >@@ -1412,7 +1412,13 @@ struct Node { > > bool hasObjectMaterializationData() > { >- return op() == MaterializeNewObject; >+ switch (op()) { >+ case MaterializeNewObject: >+ case PopulateNewObject: >+ return true; >+ default: >+ return false; >+ } > } > > ObjectMaterializationData& objectMaterializationData() >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index 521d13d7cb11f12b2f4e372edcff17de95bbb1e2..9603d2237394a8476f9ef20c6bd4c413ca4edb4a 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -252,6 +252,7 @@ namespace JSC { namespace DFG { > macro(PutHint, NodeMustGenerate) \ > macro(CheckStructureImmediate, NodeMustGenerate) \ > macro(MaterializeNewObject, NodeResultJS | NodeHasVarArgs) \ >+ macro(PopulateNewObject, NodeMustGenerate | NodeHasVarArgs) \ > macro(PhantomNewFunction, NodeResultJS | NodeMustGenerate) \ > \ > /* Nodes for misc operations. */\ >diff --git a/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp b/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp >index d0bfe14e828ec23f352185e58c6a0b4bbb874b27..529070e070d92733d832782d3b6ce06f496e6f5c 100644 >--- a/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp >@@ -52,6 +52,11 @@ public: > : Phase(graph, "object allocation sinking") > , m_ssaCalculator(graph) > , m_insertionSet(graph) >+ , m_materializedAtHead(graph) >+ , m_materializedAtTail(graph) >+ , m_pointsToAtHead(graph) >+ , m_pointsToAtTail(graph) >+ , m_weaklyAliveAtTail(graph) > { > } > >@@ -126,6 +131,7 @@ private: > > // At this point we are committed to sinking the sinking candidates. > placeMaterializationPoints(); >+ propagateMustPointToAccesses(); > lowerNonReadingOperationsOnPhantomAllocations(); > promoteSunkenFields(); > >@@ -136,7 +142,16 @@ private: > dataLog("Sinking iteration changed the graph.\n"); > return true; > } >- >+ >+ void computeFieldLiveness() >+ { >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ HashSet<Node*> alive = block->ssa->liveAtTail; >+ closeFields(alive); >+ m_weaklyAliveAtTail[block] = alive; >+ } >+ } >+ > void determineMaterializationPoints() > { > // The premise of this pass is that if there exists a point in the program where some >@@ -146,63 +161,11 @@ private: > > m_sinkCandidates.clear(); > m_materializationToEscapee.clear(); >+ m_materializationToPopulate.clear(); >+ m_materializationToHints.clear(); > m_materializationSiteToMaterializations.clear(); >- >- BlockMap<HashMap<Node*, bool>> materializedAtHead(m_graph); >- BlockMap<HashMap<Node*, bool>> materializedAtTail(m_graph); >- >- bool changed; >- do { >- if (verbose) >- dataLog("Doing iteration of materialization point placement.\n"); >- changed = false; >- for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >- HashMap<Node*, bool> materialized = materializedAtHead[block]; >- if (verbose) >- dataLog(" Looking at block ", pointerDump(block), "\n"); >- for (Node* node : *block) { >- handleNode( >- node, >- [&] () { >- materialized.add(node, false); >- }, >- [&] (Node* escapee) { >- auto iter = materialized.find(escapee); >- if (iter != materialized.end()) { >- if (verbose) >- dataLog(" ", escapee, " escapes at ", node, "\n"); >- iter->value = true; >- } >- }); >- } >- >- if (verbose) >- dataLog(" Materialized at tail of ", pointerDump(block), ": ", mapDump(materialized), "\n"); >- >- if (materialized == materializedAtTail[block]) >- continue; >- >- materializedAtTail[block] = materialized; >- changed = true; >- >- // Only propagate things to our successors if they are alive in all successors. >- // So, we prune materialized-at-tail to only include things that are live. >- Vector<Node*> toRemove; >- for (auto pair : materialized) { >- if (!block->ssa->liveAtTail.contains(pair.key)) >- toRemove.append(pair.key); >- } >- for (Node* key : toRemove) >- materialized.remove(key); >- >- for (BasicBlock* successorBlock : block->successors()) { >- for (auto pair : materialized) { >- materializedAtHead[successorBlock].add( >- pair.key, false).iterator->value |= pair.value; >- } >- } >- } >- } while (changed); >+ >+ runAnalysis(); > > // Determine the sink candidates. Broadly, a sink candidate is a node that handleNode() > // believes is sinkable, and one of the following is true: >@@ -221,13 +184,15 @@ private: > // FIXME: Implement the two other rules. > // https://bugs.webkit.org/show_bug.cgi?id=137073 (rule #1) > // https://bugs.webkit.org/show_bug.cgi?id=137074 (rule #3) >- >+ >+ computeFieldLiveness(); >+ > for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >- for (auto pair : materializedAtTail[block]) { >+ for (auto pair : m_materializedAtTail[block]) { > if (pair.value) > continue; // It was materialized. > >- if (block->ssa->liveAtTail.contains(pair.key)) >+ if (m_weaklyAliveAtTail[block].contains(pair.key)) > continue; // It might still get materialized in all of the successors. > > // We know that it died in this block and it wasn't materialized. That means that >@@ -239,7 +204,7 @@ private: > > if (m_sinkCandidates.isEmpty()) > return; >- >+ > // A materialization edge exists at any point where a node escapes but hasn't been > // materialized yet. We do this in two parts. First we find all of the nodes that cause > // escaping to happen, where the escapee had not yet been materialized. This catches >@@ -271,45 +236,40 @@ private: > // First pass: find intra-block materialization points. > for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { > HashSet<Node*> materialized; >- for (auto pair : materializedAtHead[block]) { >+ for (auto pair : m_materializedAtHead[block]) { > if (pair.value && m_sinkCandidates.contains(pair.key)) > materialized.add(pair.key); > } >- >+ > if (verbose) > dataLog("Placing materialization points in ", pointerDump(block), " with materialization set ", listDump(materialized), "\n"); > >- for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { >- Node* node = block->at(nodeIndex); >- >- handleNode( >- node, >- [&] () { }, >- [&] (Node* escapee) { >+ handleBlock( >+ block, >+ [&] (Node*) { }, >+ [&] (HashSet<Node*> escapees, Node* where) { >+ HashSet<Node*> toRemove; >+ for (Node* escapee : escapees) { > if (verbose) >- dataLog("Seeing ", escapee, " escape at ", node, "\n"); >- >- if (!m_sinkCandidates.contains(escapee)) { >- if (verbose) >- dataLog(" It's not a sink candidate.\n"); >- return; >- } >- >- if (!materialized.add(escapee).isNewEntry) { >- if (verbose) >- dataLog(" It's already materialized.\n"); >- return; >- } >- >- createMaterialize(escapee, node); >- }); >- } >+ dataLog("Seeing ", escapee, " escape at ", where, "\n"); >+ >+ if (!m_sinkCandidates.contains(escapee)) >+ toRemove.add(escapee); >+ if (!materialized.add(escapee).isNewEntry) >+ toRemove.add(escapee); >+ } >+ for (Node* remove : toRemove) >+ escapees.remove(remove); >+ >+ if (escapees.size() > 0) >+ createMaterializeAndPopulate(escapees, where); >+ }); > } > > // Second pass: find CFG edge materialization points. > for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { > for (BasicBlock* successorBlock : block->successors()) { >- for (auto pair : materializedAtHead[successorBlock]) { >+ for (auto pair : m_materializedAtHead[successorBlock]) { > Node* allocation = pair.key; > > // We only care if it is materialized in the successor. >@@ -321,7 +281,7 @@ private: > continue; > > // We only care if it isn't materialized in the predecessor. >- if (materializedAtTail[block].get(allocation)) >+ if (m_materializedAtTail[block].get(allocation)) > continue; > > // We need to decide if we put the materialization at the head of the successor, >@@ -333,13 +293,22 @@ private: > // because of what it looks like when you draw it. > bool neverMaterializedInShadow = true; > for (BasicBlock* shadowBlock : successorBlock->predecessors) { >- if (materializedAtTail[shadowBlock].get(allocation)) { >+ if (m_materializedAtTail[shadowBlock].get(allocation)) { > neverMaterializedInShadow = false; > break; > } > } > > if (neverMaterializedInShadow) { >+ // TODO: Here we should have a guarantee that all the fields >+ // have already been materialized. >+ if (!ASSERT_DISABLED) { >+ HashSet<Node*> escaping { allocation }; >+ m_materialized = m_materializedAtHead[successorBlock]; >+ m_pointsTo = m_pointsToAtHead[successorBlock]; >+ closeFields(escaping); >+ ASSERT(escaping.size() == 1); >+ } > createMaterialize(allocation, successorBlock->firstOriginNode()); > continue; > } >@@ -351,7 +320,14 @@ private: > // where the predecessor could have had multiple successors. Therefore we have > // already handled the case where the predecessor has multiple successors. > DFG_ASSERT(m_graph, block, block->numSuccessors() == 1); >- >+ // TODO: Here as well, all the fields should have been materialized >+ if (!ASSERT_DISABLED) { >+ HashSet<Node*> escaping { allocation }; >+ m_materialized = m_materializedAtTail[block]; >+ m_pointsTo = m_pointsToAtTail[block]; >+ closeFields(escaping); >+ ASSERT(escaping.size() == 1); >+ } > createMaterialize(allocation, block->terminal()); > } > } >@@ -429,9 +405,13 @@ private: > mapping.set(originalNode, phiDef->value()); > } > >+ m_materialized = m_materializedAtHead[block]; >+ m_pointsTo = m_pointsToAtHead[block]; >+ > for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { > Node* node = block->at(nodeIndex); > >+ // TODO: We need to keep the order... > for (Node* materialize : m_materializationSiteToMaterializations.get(node)) { > Node* escapee = m_materializationToEscapee.get(materialize); > m_insertionSet.insert(nodeIndex, materialize); >@@ -439,6 +419,16 @@ private: > m_insertionSet, nodeIndex, node->origin, > availabilityCalculator.m_availability, escapee, materialize); > mapping.set(escapee, materialize); >+ auto iter = m_materializationToHints.find(materialize); >+ if (iter != m_materializationToHints.end()) { >+ for (Node* hint : iter->value) >+ m_insertionSet.insert(nodeIndex, hint); >+ } >+ } >+ >+ for (Node* materialize : m_materializationSiteToMaterializations.get(node)) { >+ if (Node* populate = m_materializationToPopulate.get(materialize)) >+ m_insertionSet.insert(nodeIndex, populate); > } > > availabilityCalculator.executeNode(node); >@@ -451,14 +441,16 @@ private: > }); > > // If you cause an escape, you shouldn't see the original escapee. >+ // Now you may, because cycles. >+ /* > if (validationEnabled()) { > handleNode( > node, >- [&] () { }, >- [&] (Node* escapee) { >+ [&] (Node*) { }, >+ [&] (Node* escapee, Node*) { > DFG_ASSERT(m_graph, node, !m_sinkCandidates.contains(escapee)); > }); >- } >+ } */ > } > > NodeAndIndex terminal = block->findTerminal(); >@@ -477,6 +469,7 @@ private: > // If we have a Phi that combines materializations with the original > // phantom object, then the path with the phantom object must materialize. > >+ ASSERT(false); // for now... not sure if we need to materialize the fields... that would be annoying... > incoming = createMaterialize(allocation, upsilonWhere); > m_insertionSet.insert(upsilonInsertionPoint, incoming); > insertOSRHintsForUpdate( >@@ -504,7 +497,12 @@ private: > // Lower everything but reading operations on phantom allocations. We absolutely have to > // lower all writes so as to reveal them to the SSA calculator. We cannot lower reads > // because the whole point is that those go away completely. >- >+ >+ >+ // TODO: Probably needs to use pointsTo to follow Puts >+ // TODO: Probably also needs to follow the propagation on get and stuff >+ // TODO: this means I actually need to use handleBlock :-( >+ // We don't need to follow because we are after propagateMustPointToAccesses() > for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { > for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { > Node* node = block->at(nodeIndex); >@@ -768,6 +766,217 @@ private: > return def->value(); > } > >+ void propagateMustPointToAccesses() >+ { >+ m_graph.clearReplacements(); >+ for (BasicBlock* block : m_graph.blocksInPreOrder()) { >+ handleBlock( >+ block, >+ [&] (Node*) { }, >+ [&] (HashSet<Node*>, Node*) { }, >+ true); >+ } >+ } >+ >+ void runAnalysis() >+ { >+ m_materializedAtHead = BlockMap<HashMap<Node*, bool>>(m_graph); >+ m_materializedAtTail = BlockMap<HashMap<Node*, bool>>(m_graph); >+ m_pointsToAtHead = BlockMap<HashMap<Node*, HashMap<PromotedLocationDescriptor, Node*>>>(m_graph); >+ m_pointsToAtTail = BlockMap<HashMap<Node*, HashMap<PromotedLocationDescriptor, Node*>>>(m_graph); >+ bool changed; >+ do { >+ changed = false; >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ changed |= handleBlock( >+ block, >+ [&] (Node*) { }, >+ [&] (HashSet<Node*>, Node*) { }); >+ } >+ } while (changed); >+ } >+ >+ // Always return either null, or something pointed to that is not materialized >+ // yet (i.e., something in pointsTo itself) >+ Node* follow(Node* source) >+ { >+ if (m_pointsTo.contains(source)) >+ return source; >+ >+ Node* previous = nullptr; >+ PromotedLocationDescriptor desc; >+ switch (source->op()) { >+ case GetByOffset: >+ case GetGetterSetterByOffset: { >+ previous = follow(source->child2().node()); >+ unsigned identifierNumber = source->storageAccessData().identifierNumber; >+ desc = PromotedLocationDescriptor(NamedPropertyPLoc, identifierNumber); >+ break; >+ } >+ >+ case MultiGetByOffset: { >+ previous = follow(source->child1().node()); >+ unsigned identifierNumber = source->multiGetByOffsetData().identifierNumber; >+ desc = PromotedLocationDescriptor(NamedPropertyPLoc, identifierNumber); >+ break; >+ } >+ >+ default: >+ return nullptr; >+ } >+ >+ if (!previous) >+ return nullptr; >+ >+ auto fieldsMap = m_pointsTo.get(previous); >+ auto fieldIter = fieldsMap.find(desc); >+ if (fieldIter == fieldsMap.end()) >+ return nullptr; >+ >+ return m_pointsTo.contains(fieldIter->value) ? fieldIter->value : nullptr; >+ } >+ >+ void closeFields(HashSet<Node*>& nodes) >+ { >+ HashSet<Node*> examineFields = nodes; >+ while (!examineFields.isEmpty()) { >+ HashSet<Node*> newNodes; >+ for (Node* node : examineFields) { >+ auto iter = m_pointsTo.find(node); >+ if (iter == m_pointsTo.end()) >+ continue; >+ for (auto pair : iter->value) { >+ if (!pair.value) >+ continue; >+ auto iter = m_materialized.find(pair.value); >+ if (iter != m_materialized.end() && !iter->value >+ && nodes.add(pair.value).isNewEntry) { >+ ASSERT(m_pointsTo.contains(pair.value)); >+ newNodes.add(pair.value); >+ } >+ } >+ } >+ examineFields = WTF::move(newNodes); >+ } >+ } >+ >+ template<typename SinkCandidateFunctor, typename EscapeFunctor> >+ bool handleBlock( >+ BasicBlock* block, >+ const SinkCandidateFunctor& sinkCandidate, >+ const EscapeFunctor& escape, >+ bool fold = false) >+ { >+ auto doEscapeAllocationEscapees = [&] (HashSet<Node*> toEscape, Node* where) { >+ closeFields(toEscape); >+ escape(toEscape, where); >+ for (Node* escaping : toEscape) { >+ auto iter = m_materialized.find(escaping); >+ ASSERT(iter != m_materialized.end()); >+ iter->value = true; >+ m_pointsTo.remove(escaping); >+ } >+ }; >+ auto doEscape = [&] (Node* escapee, Node* where) { >+ if (escapee && (escapee = follow(escapee))) >+ doEscapeAllocationEscapees(HashSet<Node*> { escapee }, where); >+ }; >+ auto doSinkCandidate = [&] (Node* node) { >+ sinkCandidate(node); >+ m_materialized.add(node, false); >+ m_pointsTo.add(node, HashMap<PromotedLocationDescriptor, Node*>()); >+ }; >+ m_materialized = m_materializedAtHead[block]; >+ m_pointsTo = m_pointsToAtHead[block]; >+ for (Node* node : *block) { >+ if (fold) >+ m_graph.performSubstitution(node); >+ handleNode(node, doSinkCandidate, doEscape); >+ if (fold) { >+ Node* replacement = follow(node); >+ if (replacement && replacement != node) >+ node->replaceWith(replacement); >+ } >+ } >+ >+ // Check for "field upsilons": if there is a field where we currently have >+ // a must-point-to value and the successor disagrees (either because the successor >+ // says the owner must be materialized or because it has a different must-point-to >+ // value), we need to escape the value here. >+ HashSet<Node*> toEscape; >+ for (BasicBlock* successorBlock : block->successors()) { >+ for (auto pair : m_pointsTo) { >+ auto iter = m_materializedAtHead[successorBlock].find(pair.key); >+ if (iter != m_materializedAtHead[successorBlock].end() && iter->value) { >+ for (auto field : pair.value) { >+ if (field.value && m_pointsTo.contains(field.value)) >+ toEscape.add(field.value); >+ } >+ } else { >+ auto iter = m_pointsToAtHead[successorBlock].find(pair.key); >+ if (iter == m_pointsToAtHead[successorBlock].end()) >+ continue; >+ auto successorFieldMap = iter->value; >+ for (auto field : pair.value) { >+ if (!field.value || !m_pointsTo.contains(field.value)) >+ continue; >+ auto successorField = successorFieldMap.find(field.key); >+ if (successorField != successorFieldMap.end() >+ && successorField->value != field.value) >+ toEscape.add(field.value); >+ } >+ } >+ } >+ } >+ closeFields(toEscape); >+ doEscapeAllocationEscapees(toEscape, block->terminal()); >+ >+ if (m_materialized == m_materializedAtTail[block] && m_pointsTo == m_pointsToAtTail[block]) >+ return false; >+ >+ m_materializedAtTail[block] = m_materialized; >+ m_pointsToAtTail[block] = m_pointsTo; >+ >+ // Only propagate things to our successors if they are alive in all successors, >+ // or they are a field of a value that is alive in all successors. >+ HashSet<Node*> toKeep; >+ for (auto pair : m_materialized) { >+ if (block->ssa->liveAtTail.contains(pair.key)) >+ toKeep.add(pair.key); >+ } >+ closeFields(toKeep); >+ HashSet<Node*> toRemove; >+ for (auto pair : m_materialized) { >+ if (!toKeep.contains(pair.key)) >+ toRemove.add(pair.key); >+ } >+ for (Node* node : toRemove) { >+ m_materialized.remove(node); >+ m_pointsTo.remove(node); >+ } >+ >+ for (BasicBlock* successorBlock : block->successors()) { >+ for (auto pair : m_materialized) { >+ m_materializedAtHead[successorBlock].add( >+ pair.key, false).iterator->value |= pair.value; >+ } >+ for (auto pair : m_pointsTo) { >+ HashMap<PromotedLocationDescriptor, Node*>& successorMap = >+ m_pointsToAtHead[successorBlock].add( >+ pair.key, >+ HashMap<PromotedLocationDescriptor, Node*>()).iterator->value; >+ for (auto field : pair.value) { >+ // We ensured before that this would *always* be a new entry >+ successorMap.add(field.key, field.value); >+ } >+ } >+ } >+ >+ // IF the owner of the field IS materialized in the successor, we ONLY need to escape the value. Don't store ANYTHING in the pointsTo! >+ // It is VITALLY IMPORTANT that the guys in dom(pointsTo) are AT ALL TIMES, EXACTLY THE SAME GUYS as the guys in materialized whose value is FALSE. >+ return true; >+ } >+ > template<typename SinkCandidateFunctor, typename EscapeFunctor> > void handleNode( > Node* node, >@@ -777,20 +986,20 @@ private: > switch (node->op()) { > case NewObject: > case MaterializeNewObject: >- sinkCandidate(); >+ sinkCandidate(node); > m_graph.doToChildren( > node, > [&] (Edge edge) { >- escape(edge.node()); >+ escape(edge.node(), node); > }); > break; > > case NewFunction: >- sinkCandidate(); >+ sinkCandidate(node); > m_graph.doToChildren( > node, > [&] (Edge edge) { >- escape(edge.node()); >+ escape(edge.node(), node); > }); > break; > >@@ -800,26 +1009,36 @@ private: > case PutHint: > break; > >- case PutStructure: >+ case PutStructure: // Note that this will always be allocated, no need to record it in pointsTo > case CheckStructure: > case GetByOffset: > case MultiGetByOffset: > case GetGetterSetterByOffset: > case StoreBarrier: > case StoreBarrierWithNullCheck: { >- Node* target = node->child1().node(); >- if (!target->isObjectAllocation()) >- escape(target); >+ Node* target = follow(node->child1().node()); >+ if (target && !target->isObjectAllocation()) >+ escape(target, node); > break; > } > > case PutByOffset: { >- Node* target = node->child2().node(); >- if (!target->isObjectAllocation()) { >- escape(target); >- escape(node->child1().node()); >+ Node* target = follow(node->child2().node()); >+ if (target && target->isObjectAllocation()) { >+ auto iter = m_pointsTo.find(target); >+ if (iter != m_pointsTo.end()) { >+ auto desc = PromotedLocationDescriptor( >+ NamedPropertyPLoc, >+ node->storageAccessData().identifierNumber); >+ iter->value.add(desc, nullptr).iterator->value = >+ follow(node->child3().node()); >+ } else >+ escape(node->child3().node(), node); >+ } else { >+ escape(node->child1().node(), node); >+ escape(node->child2().node(), node); >+ escape(node->child3().node(), node); > } >- escape(node->child3().node()); > break; > } > >@@ -829,19 +1048,71 @@ private: > // PhantomStructureSelect node - since this transforms the Structure in a conditional > // way. > // https://bugs.webkit.org/show_bug.cgi?id=136924 >- escape(node->child1().node()); >- escape(node->child2().node()); >+ escape(node->child1().node(), node); >+ escape(node->child2().node(), node); > break; > > default: > m_graph.doToChildren( > node, > [&] (Edge edge) { >- escape(edge.node()); >+ escape(edge.node(), node); > }); > break; > } > } >+ >+ void createMaterializeAndPopulate(HashSet<Node*> escapees, Node* where) >+ { >+ // TODO: We need a sort that leaves minimal edges >+ HashMap<Node*, HashMap<PromotedLocationDescriptor, Node*>> depmap; >+ for (Node* escapee : escapees) { >+ auto& dep = depmap.add(escapee, HashMap<PromotedLocationDescriptor, Node*>()).iterator->value; >+ for (auto field : m_pointsTo.get(escapee)) { >+ if (field.value && m_pointsTo.contains(field.value)) >+ dep.add(field.key, field.value); >+ } >+ } >+ HashMap<Node*, Node*> materializations; >+ HashSet<Node*> materialized; >+ HashMap<Node*, HashMap<PromotedLocationDescriptor, Node*>> populateFields; >+ // TODO: We need to put PutHints for everyone that *points to* these guys!!!!!! >+ for (Node* escapee : escapees) { >+ materialized.add(escapee); >+ Node* materialization = createMaterialize(escapee, where); >+ materializations.add(escapee, materialization); >+ auto& dep = populateFields.add(escapee, HashMap<PromotedLocationDescriptor, Node*>()).iterator->value; >+ for (auto field : depmap.get(escapee)) { >+ if (!materialized.contains(field.value)) >+ dep.add(field.key, field.value); >+ } >+ >+ HashSet<Node*>& hints = m_materializationToHints.add( >+ materialization, HashSet<Node*>()).iterator->value; >+ for (auto pair : m_pointsTo) { >+ if (materialized.contains(pair.key)) >+ continue; >+ for (auto field : pair.value) { >+ if (field.value == escapee) { >+ hints.add( >+ PromotedHeapLocation(pair.key, field.key).createHint( >+ m_graph, pair.key->origin, materialization)); >+ } >+ } >+ } >+ } >+ for (Node* escapee : escapees) { >+ auto fields = populateFields.find(escapee); >+ if (fields->value.size() > 0) { >+ Node* materialization = materializations.get(escapee); >+ HashMap<PromotedLocationDescriptor, Node*> materializedFields; >+ for (auto phantom : fields->value) >+ materializedFields.add(phantom.key, materializations.get(phantom.value)); >+ m_materializationToPopulate.add(materialization, >+ createPopulate(materialization, materializedFields, where)); >+ } >+ } >+ } > > Node* createMaterialize(Node* escapee, Node* where) > { >@@ -885,6 +1156,43 @@ private: > > return result; > } >+ >+ Node* createPopulate(Node* escapee, HashMap<PromotedLocationDescriptor, Node*> fields, Node* where) >+ { >+ Node* result = nullptr; >+ >+ switch (escapee->op()) { >+ case NewObject: >+ case MaterializeNewObject: { >+ ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add(); >+ unsigned firstChild = m_graph.m_varArgChildren.size(); >+ m_graph.m_varArgChildren.append(Edge(escapee, KnownCellUse)); // TODO: THIS MUST BE BOTTOM >+ m_graph.m_varArgChildren.append(Edge(escapee, KnownCellUse)); >+ >+ for (auto& field : fields) { >+ m_graph.m_varArgChildren.append(Edge(field.value, KnownCellUse)); >+ >+ data->m_properties.append(PhantomPropertyValue(field.key.info())); >+ } >+ >+ result = m_graph.addNode( >+ SpecNone, Node::VarArg, PopulateNewObject, >+ NodeOrigin( >+ escapee->origin.semantic, >+ where->origin.forExit), >+ OpInfo(data), OpInfo(), firstChild, m_graph.m_varArgChildren.size()); >+ break; >+ } >+ >+ case NewFunction: >+ break; >+ >+ default: >+ DFG_CRASH(m_graph, escapee, "Bad escapee op"); >+ } >+ >+ return result; >+ } > > void populateMaterialize(BasicBlock* block, Node* node, Node* escapee) > { >@@ -897,9 +1205,13 @@ private: > > PromotedHeapLocation structure(StructurePLoc, escapee); > ASSERT(locations.contains(structure)); >- >+ > m_graph.m_varArgChildren.append(Edge(resolve(block, structure), KnownCellUse)); > >+ Node* populate = m_materializationToPopulate.get(node); >+ if (populate) >+ m_graph.m_varArgChildren[populate->firstChild()] = Edge(resolve(block, structure), KnownCellUse); >+ > for (unsigned i = 0; i < locations.size(); ++i) { > switch (locations[i].kind()) { > case StructurePLoc: { >@@ -909,7 +1221,7 @@ private: > > case NamedPropertyPLoc: { > Node* value = resolve(block, locations[i]); >- if (value->op() == BottomValue) { >+ if (value->op() == BottomValue || value->isPhantomAllocation()) { > // We can skip Bottoms entirely. > break; > } >@@ -968,9 +1280,11 @@ private: > break; > } > } >- >+ > SSACalculator m_ssaCalculator; > HashSet<Node*> m_sinkCandidates; >+ HashMap<Node*, Node*> m_materializationToPopulate; >+ HashMap<Node*, HashSet<Node*>> m_materializationToHints; > HashMap<Node*, Node*> m_materializationToEscapee; > HashMap<Node*, Vector<Node*>> m_materializationSiteToMaterializations; > HashMap<Node*, Vector<PromotedHeapLocation>> m_locationsForAllocation; >@@ -978,6 +1292,14 @@ private: > Vector<PromotedHeapLocation> m_indexToLocation; > HashMap<PromotedHeapLocation, Node*> m_localMapping; > InsertionSet m_insertionSet; >+ >+ BlockMap<HashMap<Node*, bool>> m_materializedAtHead; >+ BlockMap<HashMap<Node*, bool>> m_materializedAtTail; >+ HashMap<Node*, bool> m_materialized; >+ BlockMap<HashMap<Node*, HashMap<PromotedLocationDescriptor, Node*>>> m_pointsToAtHead; >+ BlockMap<HashMap<Node*, HashMap<PromotedLocationDescriptor, Node*>>> m_pointsToAtTail; >+ HashMap<Node*, HashMap<PromotedLocationDescriptor, Node*>> m_pointsTo; >+ BlockMap<HashSet<Node*>> m_weaklyAliveAtTail; > }; > > bool performObjectAllocationSinking(Graph& graph) >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index 9df30f1ce33dc9d5becf700a6f6e95e3c756f1e1..2d909e95bada065eaeb6d4999085ef68923fec1b 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -550,6 +550,7 @@ private: > case PutHint: > case CheckStructureImmediate: > case MaterializeNewObject: >+ case PopulateNewObject: > case PutStack: > case KillStack: > case GetStack: { >diff --git a/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h b/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h >index 51f7b9ee3d573b724731955414d4f2f604c05ec7..c85ebc538a1a67dce0fc39115277748cde976b93 100644 >--- a/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h >+++ b/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h >@@ -55,6 +55,12 @@ public: > { > } > >+ PromotedLocationDescriptor(WTF::HashTableDeletedValueType) >+ : m_kind(InvalidPromotedLocationKind) >+ , m_info(1) >+ { >+ } >+ > bool operator!() const { return m_kind == InvalidPromotedLocationKind; } > > PromotedLocationKind kind() const { return m_kind; } >@@ -91,6 +97,12 @@ private: > unsigned m_info; > }; > >+struct PromotedLocationDescriptorHash { >+ static unsigned hash(const PromotedLocationDescriptor& key) { return key.hash(); } >+ static bool equal(const PromotedLocationDescriptor& a, const PromotedLocationDescriptor& b) { return a == b; } >+ static const bool safeToCompareToEmptyOrDeleted = true; >+}; >+ > class PromotedHeapLocation { > public: > PromotedHeapLocation( >@@ -164,6 +176,16 @@ namespace WTF { > void printInternal(PrintStream&, JSC::DFG::PromotedLocationKind); > > template<typename T> struct DefaultHash; >+template<> struct DefaultHash<JSC::DFG::PromotedLocationDescriptor> { >+ typedef JSC::DFG::PromotedLocationDescriptorHash Hash; >+}; >+ >+template<typename T> struct HashTraits; >+template<> struct HashTraits<JSC::DFG::PromotedLocationDescriptor> : SimpleClassHashTraits<JSC::DFG::PromotedLocationDescriptor> { >+ static const bool emptyValueIsZero = false; >+}; >+ >+template<typename T> struct DefaultHash; > template<> struct DefaultHash<JSC::DFG::PromotedHeapLocation> { > typedef JSC::DFG::PromotedHeapLocationHash Hash; > }; >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index aa5a71c17f88b688e3fa5b57b8dcab22345d4f1e..ed5ac845f5bab64902017f6a3f7026e08553a886 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -276,6 +276,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) > case PutHint: > case CheckStructureImmediate: > case MaterializeNewObject: >+ case PopulateNewObject: > case PhantomDirectArguments: > case PhantomClonedArguments: > case GetMyArgumentByVal: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index d4556c4292aa4a8b18ef2dc32f7ca40a6bfe1662..b3fae987f01ebb9102e871b9141e63633889fe7f 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -4663,6 +4663,7 @@ void SpeculativeJIT::compile(Node* node) > case PutHint: > case CheckStructureImmediate: > case MaterializeNewObject: >+ case PopulateNewObject: > case PutStack: > case KillStack: > case GetStack: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index e852f72e035ff0d29644b4683f84e4b31f1ddc7b..f3ff2ec1680165ad75ec0722a979e1fca91307d7 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -4749,6 +4749,7 @@ void SpeculativeJIT::compile(Node* node) > case PutHint: > case CheckStructureImmediate: > case MaterializeNewObject: >+ case PopulateNewObject: > case PutStack: > case KillStack: > case GetStack: >diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp >index 53e7281d27d5a1030852df7e56ad18782638a8b8..b54ea9e700bbe51bef232028462780ce1531262d 100644 >--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp >+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp >@@ -457,6 +457,7 @@ private: > case PutHint: > case CheckStructureImmediate: > case MaterializeNewObject: >+ case PopulateNewObject: > case PutStack: > case KillStack: > case GetStack: >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index 28f54c8fef2f4120988a23dd8bd5a82a7c7070db..311fe7aa9290990c58427edefbe21d13ee61a2b3 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -184,6 +184,7 @@ inline CapabilityLevel canCompile(Node* node) > case PutHint: > case CheckStructureImmediate: > case MaterializeNewObject: >+ case PopulateNewObject: > case PhantomDirectArguments: > case PhantomClonedArguments: > case GetMyArgumentByVal: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >index 0132dce0a870365ffb0d9f601786c0e0c4091210..5a63688467ece404ff4a0766fb5c300a7e412708 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >@@ -845,6 +845,9 @@ private: > case MaterializeNewObject: > compileMaterializeNewObject(); > break; >+ case PopulateNewObject: >+ compilePopulateNewObject(); >+ break; > > case PhantomLocal: > case LoopHint: >@@ -4936,7 +4939,7 @@ private: > ObjectMaterializationData& data = m_node->objectMaterializationData(); > > // Lower the values first, to avoid creating values inside a control flow diamond. >- >+ > Vector<LValue, 8> values; > for (unsigned i = 0; i < data.m_properties.size(); ++i) > values.append(lowJSValue(m_graph.varArgChild(m_node, 1 + i))); >@@ -5039,6 +5042,64 @@ private: > setJSValue(m_out.phi(m_out.intPtr, results)); > } > >+ void compilePopulateNewObject() >+ { >+ ObjectMaterializationData& data = m_node->objectMaterializationData(); >+ >+ LValue object = lowCell(m_graph.varArgChild(m_node, 1)); >+ LValue butterfly = m_out.loadPtr(object, m_heaps.JSObject_butterfly); >+ >+ Vector<LValue, 8> values; >+ for (unsigned i = 0; i < data.m_properties.size(); ++i) >+ values.append(lowCell(m_graph.varArgChild(m_node, 2 + i))); >+ >+ StructureSet set; >+ m_interpreter.phiChildren()->forAllTransitiveIncomingValues( >+ m_graph.varArgChild(m_node, 0).node(), >+ [&] (Node* incoming) { >+ set.add(incoming->castConstant<Structure*>()); >+ }); >+ >+ Vector<LBasicBlock, 1> blocks(set.size()); >+ for (unsigned i = set.size(); i--;) >+ blocks[i] = FTL_NEW_BLOCK(m_out, ("PopulateNewObject case ", i)); >+ LBasicBlock dummyDefault = FTL_NEW_BLOCK(m_out, ("PopulateNewObject default case")); >+ LBasicBlock outerContinuation = FTL_NEW_BLOCK(m_out, ("PopulateNewObject continuation")); >+ >+ Vector<SwitchCase, 1> cases(set.size()); >+ for (unsigned i = set.size(); i--;) >+ cases[i] = SwitchCase(weakStructure(set[i]), blocks[i], Weight(1)); >+ m_out.switchInstruction( >+ lowCell(m_graph.varArgChild(m_node, 0)), cases, dummyDefault, Weight(0)); >+ >+ LBasicBlock outerLastNext = m_out.m_nextBlock; >+ >+ for (unsigned i = set.size(); i--;) { >+ m_out.appendTo(blocks[i], 1 + i < set.size() ? blocks[i + 1] : dummyDefault); >+ >+ Structure* structure = set[i]; >+ >+ for (PropertyMapEntry entry : structure->getPropertiesConcurrently()) { >+ for (unsigned i = data.m_properties.size(); i--;) { >+ PhantomPropertyValue value = data.m_properties[i]; >+ if (m_graph.identifiers()[value.m_identifierNumber] != entry.key) >+ continue; >+ >+ LValue base = isInlineOffset(entry.offset) ? object : butterfly; >+ storeProperty(values[i], base, value.m_identifierNumber, entry.offset); >+ break; >+ } >+ } >+ >+ m_out.jump(outerContinuation); >+ } >+ >+ m_out.appendTo(dummyDefault, outerContinuation); >+ m_out.unreachable(); >+ >+ m_out.appendTo(outerContinuation, outerLastNext); >+ } >+ > #if ENABLE(FTL_NATIVE_CALL_INLINING) > LValue getFunctionBySymbol(const CString symbol) > {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 143073
:
252332
|
252425
|
252500
|
254886
|
255679
|
255681
|
255756
|
255867
|
255926
|
256018
|
256041
|
256721