[JSC] Handle new_async_func / new_async_func_exp in DFG / FTL
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGObjectAllocationSinkingPhase.cpp
index 58e6eb5..a1b8393 100644 (file)
@@ -139,7 +139,7 @@ public:
     // once it is escaped if it still has pointers to it in order to
     // replace any use of those pointers by the corresponding
     // materialization
-    enum class Kind { Escaped, Object, Activation, Function, NewArrowFunction };
+    enum class Kind { Escaped, Object, Activation, Function, GeneratorFunction, AsyncFunction };
 
     explicit Allocation(Node* identifier = nullptr, Kind kind = Kind::Escaped)
         : m_identifier(identifier)
@@ -233,12 +233,7 @@ public:
 
     bool isFunctionAllocation() const
     {
-        return m_kind == Kind::Function || m_kind == Kind::NewArrowFunction;
-    }
-    
-    bool isArrowFunctionAllocation() const
-    {
-        return m_kind == Kind::NewArrowFunction;
+        return m_kind == Kind::Function || m_kind == Kind::GeneratorFunction || m_kind == Kind::AsyncFunction;
     }
 
     bool operator==(const Allocation& other) const
@@ -273,9 +268,13 @@ public:
         case Kind::Function:
             out.print("Function");
             break;
-                
-        case Kind::NewArrowFunction:
-            out.print("NewArrowFunction");
+
+        case Kind::GeneratorFunction:
+            out.print("GeneratorFunction");
+            break;
+
+        case Kind::AsyncFunction:
+            out.print("AsyncFunction");
             break;
 
         case Kind::Activation:
@@ -418,7 +417,7 @@ public:
 
     HashMap<Node*, Allocation> takeEscapees()
     {
-        return WTF::move(m_escapees);
+        return WTFMove(m_escapees);
     }
 
     void escape(Node* node)
@@ -644,14 +643,14 @@ private:
         if (allocation.isEscapedAllocation())
             return;
 
-        Allocation unescaped = WTF::move(allocation);
+        Allocation unescaped = WTFMove(allocation);
         allocation = Allocation(unescaped.identifier(), Allocation::Kind::Escaped);
 
         for (const auto& entry : unescaped.fields())
             escapeAllocation(entry.value);
 
         if (m_wantEscapees)
-            m_escapees.add(unescaped.identifier(), WTF::move(unescaped));
+            m_escapees.add(unescaped.identifier(), WTFMove(unescaped));
     }
 
     void prune()
@@ -727,7 +726,7 @@ private:
     {
         m_graph.computeRefCounts();
         m_graph.initializeNodeOwners();
-        m_graph.m_dominators.computeIfNecessary(m_graph);
+        m_graph.ensureDominators();
         performLivenessAnalysis(m_graph);
         performOSRAvailabilityAnalysis(m_graph);
         m_combinedLiveness = CombinedLiveness(m_graph);
@@ -837,23 +836,27 @@ private:
             break;
 
         case NewFunction:
-        case NewArrowFunction: {
-            bool isArrowFunction = node->op() == NewArrowFunction;
-            if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid()) {
+        case NewGeneratorFunction:
+        case NewAsyncFunction: {
+            if (isStillValid(node->castOperand<FunctionExecutable*>()->singletonFunction())) {
                 m_heap.escape(node->child1().node());
                 break;
             }
-            
-            target = &m_heap.newAllocation(node, isArrowFunction ? Allocation::Kind::NewArrowFunction : Allocation::Kind::Function);
+
+            if (node->op() == NewGeneratorFunction)
+                target = &m_heap.newAllocation(node, Allocation::Kind::GeneratorFunction);
+            else if (node->op() == NewAsyncFunction)
+                target = &m_heap.newAllocation(node, Allocation::Kind::AsyncFunction);
+            else
+                target = &m_heap.newAllocation(node, Allocation::Kind::Function);
+
             writes.add(FunctionExecutablePLoc, LazyNode(node->cellOperand()));
             writes.add(FunctionActivationPLoc, LazyNode(node->child1().node()));
-            if (isArrowFunction)
-                writes.add(ArrowFunctionBoundThisPLoc, LazyNode(node->child2().node()));
             break;
         }
 
         case CreateActivation: {
-            if (node->castOperand<SymbolTable*>()->singletonScope()->isStillValid()) {
+            if (isStillValid(node->castOperand<SymbolTable*>()->singletonScope())) {
                 m_heap.escape(node->child1().node());
                 break;
             }
@@ -1018,14 +1021,6 @@ private:
                 m_heap.escape(node->child1().node());
             break;
 
-        case LoadArrowFunctionThis:
-            target = m_heap.onlyLocalAllocation(node->child1().node());
-            if (target && target->isArrowFunctionAllocation())
-                exactRead = ArrowFunctionBoundThisPLoc;
-            else
-                m_heap.escape(node->child1().node());
-            break;
-        
         case GetScope:
             target = m_heap.onlyLocalAllocation(node->child1().node());
             if (target && target->isFunctionAllocation())
@@ -1224,7 +1219,7 @@ private:
                     if (mustEscape)
                         escapingOnEdge.add(entry.key, entry.value);
                 }
-                placeMaterializations(WTF::move(escapingOnEdge), block->terminal());
+                placeMaterializations(WTFMove(escapingOnEdge), block->terminal());
             }
         }
 
@@ -1255,7 +1250,7 @@ private:
 
             for (const auto& field : entry.value.fields()) {
                 ASSERT(m_sinkCandidates.contains(entry.key) || !escapees.contains(field.value));
-                if (escapees.contains(field.value) && !field.key.neededForMaterialization())
+                if (escapees.contains(field.value))
                     hints.append(PromotedHeapLocation(entry.key, field.key));
             }
         }
@@ -1338,7 +1333,7 @@ private:
             // We need to insert *after* the current position
             if (firstPos != toMaterialize.end())
                 ++firstPos;
-            firstPos = toMaterialize.insert(firstPos, WTF::move(allocation));
+            firstPos = toMaterialize.insert(firstPos, WTFMove(allocation));
         };
 
         // Nodes that no other unmaterialized node points to will be
@@ -1347,7 +1342,7 @@ private:
         auto lastPos = toMaterialize.end();
         auto materializeLast = [&] (Allocation&& allocation) {
             materialize(allocation.identifier());
-            lastPos = toMaterialize.insert(lastPos, WTF::move(allocation));
+            lastPos = toMaterialize.insert(lastPos, WTFMove(allocation));
         };
 
         // These are the promoted locations that contains some of the
@@ -1368,12 +1363,12 @@ private:
                     continue;
 
                 if (dependencies.find(entry.key)->value.isEmpty()) {
-                    materializeFirst(WTF::move(entry.value));
+                    materializeFirst(WTFMove(entry.value));
                     continue;
                 }
 
                 if (reverseDependencies.find(entry.key)->value.isEmpty()) {
-                    materializeLast(WTF::move(entry.value));
+                    materializeLast(WTFMove(entry.value));
                     continue;
                 }
             }
@@ -1384,7 +1379,7 @@ private:
             // first.
             if (materialized.isEmpty()) {
                 uint64_t maxEvaluation = 0;
-                Allocation* bestAllocation;
+                Allocation* bestAllocation = nullptr;
                 for (auto& entry : escapees) {
                     if (!forMaterialization.find(entry.key)->value.isEmpty())
                         continue;
@@ -1398,7 +1393,7 @@ private:
                 }
                 RELEASE_ASSERT(maxEvaluation > 0);
 
-                materializeFirst(WTF::move(*bestAllocation));
+                materializeFirst(WTFMove(*bestAllocation));
             }
             RELEASE_ASSERT(!materialized.isEmpty());
 
@@ -1457,11 +1452,14 @@ private:
                 OpInfo(set), OpInfo(data), 0, 0);
         }
 
-        case Allocation::Kind::NewArrowFunction:
+        case Allocation::Kind::AsyncFunction:
+        case Allocation::Kind::GeneratorFunction:
         case Allocation::Kind::Function: {
             FrozenValue* executable = allocation.identifier()->cellOperand();
             
-            NodeType nodeType = allocation.kind() == Allocation::Kind::NewArrowFunction ? NewArrowFunction : NewFunction;
+            NodeType nodeType =
+                allocation.kind() == Allocation::Kind::GeneratorFunction ? NewGeneratorFunction :
+                allocation.kind() == Allocation::Kind::AsyncFunction ? NewAsyncFunction : NewFunction;
             
             return m_graph.addNode(
                 allocation.identifier()->prediction(), nodeType,
@@ -1704,6 +1702,8 @@ private:
                     m_localMapping.set(location, m_bottom);
 
                     if (m_sinkCandidates.contains(node)) {
+                        if (verbose)
+                            dataLog("For sink candidate ", node, " found location ", location, "\n");
                         m_insertionSet.insert(
                             nodeIndex + 1,
                             location.createHint(
@@ -1770,6 +1770,8 @@ private:
 
                         doLower = true;
 
+                        if (verbose)
+                            dataLog("Creating hint with value ", nodeValue, " before ", node, "\n");
                         m_insertionSet.insert(
                             nodeIndex + 1,
                             location.createHint(
@@ -1791,11 +1793,18 @@ private:
                         node->convertToPhantomNewObject();
                         break;
 
-                    case NewArrowFunction:
                     case NewFunction:
                         node->convertToPhantomNewFunction();
                         break;
 
+                    case NewGeneratorFunction:
+                        node->convertToPhantomNewGeneratorFunction();
+                        break;
+
+                    case NewAsyncFunction:
+                        node->convertToPhantomNewAsyncFunction();
+                        break;
+
                     case CreateActivation:
                         node->convertToPhantomCreateActivation();
                         break;
@@ -1861,7 +1870,8 @@ private:
         ASSERT(def->value());
 
         Node* result = def->value();
-
+        if (result->replacement())
+            result = result->replacement();
         ASSERT(!result->replacement());
 
         m_localMapping.add(location, result);
@@ -1901,6 +1911,13 @@ private:
 
     void insertOSRHintsForUpdate(unsigned nodeIndex, NodeOrigin origin, bool& canExit, AvailabilityMap& availability, Node* escapee, Node* materialization)
     {
+        if (verbose) {
+            dataLog("Inserting OSR hints at ", origin, ":\n");
+            dataLog("    Escapee: ", escapee, "\n");
+            dataLog("    Materialization: ", materialization, "\n");
+            dataLog("    Availability: ", availability, "\n");
+        }
+        
         // We need to follow() the value in the heap.
         // Consider the following graph:
         //
@@ -1973,7 +1990,7 @@ private:
 
                 case NamedPropertyPLoc: {
                     ASSERT(location.base() == allocation.identifier());
-                    data.m_properties.append(PhantomPropertyValue(location.info()));
+                    data.m_properties.append(location.descriptor());
                     Node* value = resolve(block, location);
                     if (m_sinkCandidates.contains(value))
                         m_graph.m_varArgChildren.append(m_bottom);
@@ -2023,7 +2040,7 @@ private:
 
                 case ClosureVarPLoc: {
                     ASSERT(location.base() == allocation.identifier());
-                    data.m_properties.append(PhantomPropertyValue(location.info()));
+                    data.m_properties.append(location.descriptor());
                     Node* value = resolve(block, location);
                     if (m_sinkCandidates.contains(value))
                         m_graph.m_varArgChildren.append(m_bottom);
@@ -2044,10 +2061,10 @@ private:
         }
         
         case NewFunction:
-        case NewArrowFunction: {
-            bool isArrowFunction = node->op() == NewArrowFunction;
+        case NewGeneratorFunction:
+        case NewAsyncFunction: {
             Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);
-            ASSERT(locations.size() == (isArrowFunction ? 3 : 2));
+            ASSERT(locations.size() == 2);
                 
             PromotedHeapLocation executable(FunctionExecutablePLoc, allocation.identifier());
             ASSERT_UNUSED(executable, locations.contains(executable));
@@ -2056,13 +2073,6 @@ private:
             ASSERT(locations.contains(activation));
 
             node->child1() = Edge(resolve(block, activation), KnownCellUse);
-            
-            if (isArrowFunction) {
-                PromotedHeapLocation boundThis(ArrowFunctionBoundThisPLoc, allocation.identifier());
-                ASSERT(locations.contains(boundThis));
-                node->child2() = Edge(resolve(block, boundThis), CellUse);
-            }
-            
             break;
         }
 
@@ -2118,7 +2128,6 @@ private:
                 data->identifierNumber = identifierNumber;
 
                 return m_graph.addNode(
-                    SpecNone,
                     PutByOffset,
                     origin.takeValidExit(canExit),
                     OpInfo(data),
@@ -2153,7 +2162,6 @@ private:
             }
 
             return m_graph.addNode(
-                SpecNone,
                 MultiPutByOffset,
                 origin.takeValidExit(canExit),
                 OpInfo(data),
@@ -2164,7 +2172,6 @@ private:
 
         case ClosureVarPLoc: {
             return m_graph.addNode(
-                SpecNone,
                 PutClosureVar,
                 origin.takeValidExit(canExit),
                 OpInfo(location.info()),
@@ -2179,6 +2186,15 @@ private:
         }
     }
 
+    // This is a great way of asking value->isStillValid() without having to worry about getting
+    // different answers. It turns out that this analysis works OK regardless of what this
+    // returns but breaks badly if this changes its mind for any particular InferredValue. This
+    // method protects us from that.
+    bool isStillValid(InferredValue* value)
+    {
+        return m_validInferredValues.add(value, value->isStillValid()).iterator->value;
+    }
+
     SSACalculator m_pointerSSA;
     SSACalculator m_allocationSSA;
     HashSet<Node*> m_sinkCandidates;
@@ -2189,6 +2205,8 @@ private:
     InsertionSet m_insertionSet;
     CombinedLiveness m_combinedLiveness;
 
+    HashMap<InferredValue*, bool> m_validInferredValues;
+
     HashMap<Node*, Node*> m_materializationToEscapee;
     HashMap<Node*, Vector<Node*>> m_materializationSiteToMaterializations;
     HashMap<Node*, Vector<PromotedHeapLocation>> m_materializationSiteToRecoveries;
@@ -2206,7 +2224,6 @@ private:
 
 bool performObjectAllocationSinking(Graph& graph)
 {
-    SamplingRegion samplingRegion("DFG Object Allocation Sinking Phase");
     return runPhase<ObjectAllocationSinkingPhase>(graph);
 }