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/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 7a92f90..0db746b 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,21 @@
+2013-03-18  Filip Pizlo  <fpizlo@apple.com>
+
+        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):
+
 2013-03-19  Gabor Rapcsanyi  <rgabor@webkit.org>
 
         Implement and32 on ARMv7 and ARM traditional platforms
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>