DFG should optimize StringObject.length and StringOrStringObject.length
https://bugs.webkit.org/show_bug.cgi?id=112658

Reviewed by Mark Hahnenberg.
        
Implemented by injecting a ToString(StringObject:@a) or ToString(StringOrStringObject:@a) prior
to GetArrayLength with ArrayMode(Array::String) if @a is predicted StringObject or
StringOrStringObject.

* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::createToString):
(FixupPhase):
(JSC::DFG::FixupPhase::attemptToForceStringArrayModeByToStringConversion):
(JSC::DFG::FixupPhase::convertStringAddUse):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@146247 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 29472f0..740dc88 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -725,6 +725,17 @@
                 }
             } else
                 arrayMode = arrayMode.refine(node->child1()->prediction(), node->prediction());
+            
+            if (arrayMode.type() == Array::Generic) {
+                // Check if the input is something that we can't get array length for, but for which we
+                // could insert some conversions in order to transform it into something that we can do it
+                // for.
+                if (node->child1()->shouldSpeculateStringObject())
+                    attemptToForceStringArrayModeByToStringConversion<StringObjectUse>(arrayMode, node);
+                else if (node->child1()->shouldSpeculateStringOrStringObject())
+                    attemptToForceStringArrayModeByToStringConversion<StringOrStringObjectUse>(arrayMode, node);
+            }
+            
             if (!arrayMode.supportsLength())
                 break;
             node->setOp(GetArrayLength);
@@ -887,6 +898,26 @@
     }
     
     template<UseKind useKind>
+    Node* createToString(Node* node, Edge edge)
+    {
+        return m_insertionSet.insertNode(
+            m_indexInBlock, SpecString, ToString, node->codeOrigin,
+            Edge(edge.node(), useKind));
+    }
+    
+    template<UseKind useKind>
+    void attemptToForceStringArrayModeByToStringConversion(ArrayMode& arrayMode, Node* node)
+    {
+        ASSERT(arrayMode == ArrayMode(Array::Generic));
+        
+        if (!canOptimizeStringObjectAccess(node->codeOrigin))
+            return;
+        
+        node->child1().setNode(createToString<useKind>(node, node->child1()));
+        arrayMode = ArrayMode(Array::String);
+    }
+    
+    template<UseKind useKind>
     bool isStringObjectUse()
     {
         switch (useKind) {
@@ -916,9 +947,7 @@
         // FIXME: We ought to be able to have a ToPrimitiveToString node.
         
         observeUseKindOnNode<useKind>(edge.node());
-        edge = Edge(m_insertionSet.insertNode(
-            m_indexInBlock, SpecString, ToString, node->codeOrigin,
-            Edge(edge.node(), useKind)), KnownStringUse);
+        edge = Edge(createToString<useKind>(node, edge), KnownStringUse);
     }
     
     template<UseKind leftUseKind>