fourthTier: DFG shouldn't exit just because a String GetByVal went out-of-bounds
https://bugs.webkit.org/show_bug.cgi?id=117906

Source/JavaScriptCore:

Reviewed by Mark Hahnenberg.

This does the obvious thing, but also makes sure that out-of-bounds accesses
don't fall off into a C call, but try to do the fast thing if the prototype
chain is sane. We ought to probably do this for other array accesses in the
future, as well, since it's so darn easy.

* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetByValOnString):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::objectPrototypeIsSane):
(JSC):
(JSC::JSGlobalObject::arrayPrototypeChainIsSane):
(JSC::JSGlobalObject::stringPrototypeChainIsSane):
* runtime/JSGlobalObject.h:
(JSGlobalObject):

LayoutTests:

Reviewed by Mark Hahnenberg.

The out-of-bounds benchmark that isn't insane speeds up by 22x in this
patch.

* fast/js/regress/script-tests/string-get-by-val-out-of-bounds-insane.js: Added.
(foo):
* fast/js/regress/script-tests/string-get-by-val-out-of-bounds.js: Added.
(foo):
* fast/js/regress/string-get-by-val-out-of-bounds-expected.txt: Added.
* fast/js/regress/string-get-by-val-out-of-bounds-insane-expected.txt: Added.
* fast/js/regress/string-get-by-val-out-of-bounds-insane.html: Added.
* fast/js/regress/string-get-by-val-out-of-bounds.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@153244 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 637ac81..e9ce574 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -898,7 +898,19 @@
             forNode(node).makeTop();
             break;
         case Array::String:
-            forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
+            if (node->arrayMode().isOutOfBounds()) {
+                // If the watchpoint was still valid we could totally set this to be
+                // SpecString | SpecOther. Except that we'd have to be careful. If we
+                // tested the watchpoint state here then it could change by the time
+                // we got to the backend. So to do this right, we'd have to get the
+                // fixup phase to check the watchpoint state and then bake into the
+                // GetByVal operation the fact that we're using a watchpoint, using
+                // something like Array::SaneChain (except not quite, because that
+                // implies an in-bounds access). None of this feels like it's worth it,
+                // so we're going with TOP for now.
+                forNode(node).makeTop();
+            } else
+                forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
             break;
         case Array::Arguments:
             forNode(node).makeTop();