Title: [134168] trunk/Source/_javascript_Core
Revision
134168
Author
[email protected]
Date
2012-11-10 18:56:12 -0800 (Sat, 10 Nov 2012)

Log Message

DFG should optimize out the NaN check on loads from double arrays if the array prototype chain is having a great time
https://bugs.webkit.org/show_bug.cgi?id=101718

Reviewed by Geoffrey Garen.

If we're reading from a JSArray in double mode, where the array's structure is
primordial (all aspects of the structure are unchanged except for indexing type),
and the result of the load is used in arithmetic that is known to not distinguish
between NaN and undefined, then we should not emit a NaN check. Looks like a 5%
win on navier-stokes.
        
Also fixed an OpInfo initialization goof for String ops that was revealed by this
change.

* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::arraySpeculationToString):
* dfg/DFGArrayMode.h:
(JSC::DFG::ArrayMode::isSaneChain):
(ArrayMode):
(JSC::DFG::ArrayMode::isInBounds):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeFlags.cpp:
(JSC::DFG::nodeFlagsAsString):
* dfg/DFGNodeFlags.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::arrayPrototypeChainIsSane):
(JSC):
* runtime/JSGlobalObject.h:
(JSGlobalObject):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (134167 => 134168)


--- trunk/Source/_javascript_Core/ChangeLog	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-11-11 02:56:12 UTC (rev 134168)
@@ -1,5 +1,49 @@
 2012-11-10  Filip Pizlo  <[email protected]>
 
+        DFG should optimize out the NaN check on loads from double arrays if the array prototype chain is having a great time
+        https://bugs.webkit.org/show_bug.cgi?id=101718
+
+        Reviewed by Geoffrey Garen.
+
+        If we're reading from a JSArray in double mode, where the array's structure is
+        primordial (all aspects of the structure are unchanged except for indexing type),
+        and the result of the load is used in arithmetic that is known to not distinguish
+        between NaN and undefined, then we should not emit a NaN check. Looks like a 5%
+        win on navier-stokes.
+        
+        Also fixed an OpInfo initialization goof for String ops that was revealed by this
+        change.
+
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::arraySpeculationToString):
+        * dfg/DFGArrayMode.h:
+        (JSC::DFG::ArrayMode::isSaneChain):
+        (ArrayMode):
+        (JSC::DFG::ArrayMode::isInBounds):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsic):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeFlags.cpp:
+        (JSC::DFG::nodeFlagsAsString):
+        * dfg/DFGNodeFlags.h:
+        (DFG):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::arrayPrototypeChainIsSane):
+        (JSC):
+        * runtime/JSGlobalObject.h:
+        (JSGlobalObject):
+
+2012-11-10  Filip Pizlo  <[email protected]>
+
         DFG constant folding and CFG simplification should be smart enough to know that if a logical op's operand is proven to have a non-masquerading structure then it always evaluates to true
         https://bugs.webkit.org/show_bug.cgi?id=101511
 

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-11-11 02:56:12 UTC (rev 134168)
@@ -922,7 +922,9 @@
             if (node.arrayMode().isOutOfBounds()) {
                 clobberWorld(node.codeOrigin, indexInBlock);
                 forNode(nodeIndex).makeTop();
-            } else
+            } else if (node.arrayMode().isSaneChain())
+                forNode(nodeIndex).set(SpecDouble);
+            else
                 forNode(nodeIndex).set(SpecDoubleReal);
             break;
         case Array::Contiguous:

Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2012-11-11 02:56:12 UTC (rev 134168)
@@ -409,6 +409,8 @@
 const char* arraySpeculationToString(Array::Speculation speculation)
 {
     switch (speculation) {
+    case Array::SaneChain:
+        return "SaneChain";
     case Array::InBounds:
         return "InBounds";
     case Array::ToHole:

Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.h (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.h	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.h	2012-11-11 02:56:12 UTC (rev 134168)
@@ -86,9 +86,10 @@
 };
 
 enum Speculation {
-    InBounds,
-    ToHole,
-    OutOfBounds
+    SaneChain, // In bounds and the array prototype chain is still intact, i.e. loading a hole doesn't require special treatment.
+    InBounds, // In bounds and not loading a hole.
+    ToHole, // Potentially storing to a hole.
+    OutOfBounds // Out-of-bounds access and anything can happen.
 };
 enum Conversion {
     AsIs,
@@ -223,9 +224,20 @@
         return arrayClass() == Array::OriginalArray;
     }
     
+    bool isSaneChain() const
+    {
+        return speculation() == Array::SaneChain;
+    }
+    
     bool isInBounds() const
     {
-        return speculation() == Array::InBounds;
+        switch (speculation()) {
+        case Array::SaneChain:
+        case Array::InBounds:
+            return true;
+        default:
+            return false;
+        }
     }
     
     bool mayStoreToHole() const

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2012-11-11 02:56:12 UTC (rev 134168)
@@ -1703,7 +1703,7 @@
 
         int thisOperand = registerOffset + argumentToOperand(0);
         int indexOperand = registerOffset + argumentToOperand(1);
-        NodeIndex charCode = addToGraph(StringCharCodeAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand));
+        NodeIndex charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), getToInt32(indexOperand));
 
         if (usesResult)
             set(resultOperand, charCode);
@@ -1716,7 +1716,7 @@
 
         int thisOperand = registerOffset + argumentToOperand(0);
         int indexOperand = registerOffset + argumentToOperand(1);
-        NodeIndex charCode = addToGraph(StringCharAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand));
+        NodeIndex charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), getToInt32(indexOperand));
 
         if (usesResult)
             set(resultOperand, charCode);

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2012-11-11 02:56:12 UTC (rev 134168)
@@ -134,6 +134,16 @@
                     m_graph[node.child2()].prediction()));
             
             blessArrayOperation(node.child1(), node.child2(), 2);
+            
+            ArrayMode arrayMode = node.arrayMode();
+            if (arrayMode.type() == Array::Double
+                && arrayMode.arrayClass() == Array::OriginalArray
+                && arrayMode.speculation() == Array::InBounds
+                && arrayMode.conversion() == Array::AsIs
+                && m_graph.globalObjectFor(node.codeOrigin)->arrayPrototypeChainIsSane()
+                && !(node.flags() & NodeUsedAsOther))
+                node.setArrayMode(arrayMode.withSpeculation(Array::SaneChain));
+            
             break;
         }
         case StringCharAt:

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeFlags.cpp (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGNodeFlags.cpp	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeFlags.cpp	2012-11-11 02:56:12 UTC (rev 134168)
@@ -112,6 +112,12 @@
             ptr.strcat("PureNum");
             hasPrinted = true;
         }
+        if (flags & NodeUsedAsOther) {
+            if (hasPrinted)
+                ptr.strcat("|");
+            ptr.strcat("UseAsOther");
+            hasPrinted = true;
+        }
     }
     
     if (flags & NodeMayOverflow) {

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeFlags.h (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGNodeFlags.h	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeFlags.h	2012-11-11 02:56:12 UTC (rev 134168)
@@ -52,14 +52,15 @@
 #define NodeMayOverflow           0x100
 #define NodeMayNegZero            0x200
                                 
-#define NodeBackPropMask         0x1C00
+#define NodeBackPropMask         0x3C00
 #define NodeUseBottom             0x000
 #define NodeUsedAsNumber          0x400 // The result of this computation may be used in a context that observes fractional results.
 #define NodeNeedsNegZero          0x800 // The result of this computation may be used in a context that observes -0.
-#define NodeUsedAsValue           (NodeUsedAsNumber | NodeNeedsNegZero)
-#define NodeUsedAsInt            0x1000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
+#define NodeUsedAsOther          0x1000 // The result of this computation may be used in a context that distinguishes between NaN and other things (like undefined).
+#define NodeUsedAsValue          (NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther)
+#define NodeUsedAsInt            0x2000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
 
-#define NodeDoesNotExit          0x2000 // This flag is negated to make it natural for the default to be that a node does exit.
+#define NodeDoesNotExit          0x4000 // This flag is negated to make it natural for the default to be that a node does exit.
 
 typedef uint16_t NodeFlags;
 

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2012-11-11 02:56:12 UTC (rev 134168)
@@ -184,7 +184,7 @@
         case BitURShift: {
             changed |= setPrediction(SpecInt32);
             flags |= NodeUsedAsInt;
-            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
+            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);
             changed |= m_graph[node.child1()].mergeFlags(flags);
             changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
@@ -193,7 +193,7 @@
         case ValueToInt32: {
             changed |= setPrediction(SpecInt32);
             flags |= NodeUsedAsInt;
-            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
+            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);
             changed |= m_graph[node.child1()].mergeFlags(flags);
             break;
         }
@@ -221,7 +221,7 @@
         case StringCharCodeAt: {
             changed |= mergePrediction(SpecInt32);
             changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
             break;
         }
 
@@ -254,6 +254,8 @@
             
             if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
                 flags &= ~NodeNeedsNegZero;
+            if (m_graph[node.child1()].hasNumberResult() || m_graph[node.child2()].hasNumberResult())
+                flags &= ~NodeUsedAsOther;
             
             changed |= m_graph[node.child1()].mergeFlags(flags);
             changed |= m_graph[node.child2()].mergeFlags(flags);
@@ -273,6 +275,7 @@
             
             if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
                 flags &= ~NodeNeedsNegZero;
+            flags &= ~NodeUsedAsOther;
             
             changed |= m_graph[node.child1()].mergeFlags(flags);
             changed |= m_graph[node.child2()].mergeFlags(flags);
@@ -292,6 +295,7 @@
 
             if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
                 flags &= ~NodeNeedsNegZero;
+            flags &= ~NodeUsedAsOther;
             
             changed |= m_graph[node.child1()].mergeFlags(flags);
             changed |= m_graph[node.child2()].mergeFlags(flags);
@@ -306,6 +310,8 @@
                     changed |= mergePrediction(speculatedDoubleTypeForPrediction(m_graph[node.child1()].prediction()));
             }
 
+            flags &= ~NodeUsedAsOther;
+
             changed |= m_graph[node.child1()].mergeFlags(flags);
             break;
             
@@ -323,6 +329,8 @@
             }
 
             flags |= NodeUsedAsNumber;
+            flags &= ~NodeUsedAsOther;
+
             changed |= m_graph[node.child1()].mergeFlags(flags);
             changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
@@ -345,6 +353,8 @@
             // no matter what, and always forces its inputs to check as well.
             
             flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+            flags &= ~NodeUsedAsOther;
+
             changed |= m_graph[node.child1()].mergeFlags(flags);
             changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
@@ -368,6 +378,8 @@
             // no matter what, and always forces its inputs to check as well.
             
             flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+            flags &= ~NodeUsedAsOther;
+
             changed |= m_graph[node.child1()].mergeFlags(flags);
             changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
@@ -385,7 +397,9 @@
                     changed |= mergePrediction(SpecDouble);
             }
             
-            flags |= NodeUsedAsValue;
+            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+            flags &= ~NodeUsedAsOther;
+
             changed |= m_graph[node.child1()].mergeFlags(flags);
             changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
@@ -393,7 +407,9 @@
             
         case ArithSqrt: {
             changed |= setPrediction(SpecDouble);
-            changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue);
+            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
+            flags &= ~NodeUsedAsOther;
+            changed |= m_graph[node.child1()].mergeFlags(flags);
             break;
         }
             
@@ -405,7 +421,6 @@
             else
                 changed |= mergePrediction(speculatedDoubleTypeForPrediction(child));
 
-            flags &= ~NodeNeedsNegZero;
             changed |= m_graph[node.child1()].mergeFlags(flags);
             break;
         }
@@ -448,13 +463,13 @@
                 changed |= mergePrediction(node.getHeapPrediction());
 
             changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
             break;
         }
             
         case GetMyArgumentByValSafe: {
             changed |= mergePrediction(node.getHeapPrediction());
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
             break;
         }
             
@@ -555,7 +570,7 @@
             
         case NewArrayWithSize: {
             changed |= setPrediction(SpecArray);
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue | NodeUsedAsInt);
             break;
         }
             
@@ -572,7 +587,7 @@
         case StringCharAt: {
             changed |= setPrediction(SpecString);
             changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
             break;
         }
             
@@ -581,7 +596,7 @@
             for (unsigned childIdx = node.firstChild();
                  childIdx < node.firstChild() + node.numChildren();
                  ++childIdx)
-                changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber);
+                changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther);
             break;
         }
             
@@ -646,7 +661,7 @@
         
         case PutByVal:
             changed |= m_graph[m_graph.varArgChild(node, 0)].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
             changed |= m_graph[m_graph.varArgChild(node, 2)].mergeFlags(NodeUsedAsValue);
             break;
 

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-11-11 02:56:12 UTC (rev 134168)
@@ -29,9 +29,11 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "ArrayPrototype.h"
 #include "DFGCallArrayAllocatorSlowPathGenerator.h"
 #include "DFGSlowPathGenerator.h"
 #include "JSActivation.h"
+#include "ObjectPrototype.h"
 
 namespace JSC { namespace DFG {
 
@@ -2702,6 +2704,13 @@
         }
         case Array::Double: {
             if (node.arrayMode().isInBounds()) {
+                if (node.arrayMode().isSaneChain()) {
+                    JSGlobalObject* globalObject = m_jit.globalObjectFor(node.codeOrigin);
+                    ASSERT(globalObject->arrayPrototypeChainIsSane());
+                    globalObject->arrayPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+                    globalObject->objectPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+                }
+                
                 SpeculateStrictInt32Operand property(this, node.child2());
                 StorageOperand storage(this, node.child3());
             
@@ -2715,7 +2724,8 @@
             
                 FPRTemporary result(this);
                 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
-                speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
+                if (!node.arrayMode().isSaneChain())
+                    speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
                 doubleResult(result.fpr(), m_compileIndex);
                 break;
             }

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (134167 => 134168)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-11-11 02:56:12 UTC (rev 134168)
@@ -29,8 +29,10 @@
 #if ENABLE(DFG_JIT)
 
 #include "Arguments.h"
+#include "ArrayPrototype.h"
 #include "DFGCallArrayAllocatorSlowPathGenerator.h"
 #include "DFGSlowPathGenerator.h"
+#include "ObjectPrototype.h"
 
 namespace JSC { namespace DFG {
 
@@ -2654,6 +2656,13 @@
 
         case Array::Double: {
             if (node.arrayMode().isInBounds()) {
+                if (node.arrayMode().isSaneChain()) {
+                    JSGlobalObject* globalObject = m_jit.globalObjectFor(node.codeOrigin);
+                    ASSERT(globalObject->arrayPrototypeChainIsSane());
+                    globalObject->arrayPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+                    globalObject->objectPrototype()->structure()->addTransitionWatchpoint(speculationWatchpoint());
+                }
+                
                 SpeculateStrictInt32Operand property(this, node.child2());
                 StorageOperand storage(this, node.child3());
             
@@ -2667,7 +2676,8 @@
             
                 FPRTemporary result(this);
                 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), result.fpr());
-                speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
+                if (!node.arrayMode().isSaneChain())
+                    speculationCheck(OutOfBounds, JSValueRegs(), NoNode, m_jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, result.fpr(), result.fpr()));
                 doubleResult(result.fpr(), m_compileIndex);
                 break;
             }

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (134167 => 134168)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2012-11-11 02:56:12 UTC (rev 134168)
@@ -437,6 +437,14 @@
     }
 }
 
+bool JSGlobalObject::arrayPrototypeChainIsSane()
+{
+    return !hasIndexedProperties(m_arrayPrototype->structure()->indexingType())
+        && m_arrayPrototype->prototype() == m_objectPrototype.get()
+        && !hasIndexedProperties(m_objectPrototype->structure()->indexingType())
+        && m_objectPrototype->prototype().isNull();
+}
+
 void JSGlobalObject::createThrowTypeError(ExecState* exec)
 {
     JSFunction* thrower = JSFunction::create(exec, this, 0, String(), globalFuncThrowTypeError);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (134167 => 134168)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2012-11-11 00:55:37 UTC (rev 134167)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2012-11-11 02:56:12 UTC (rev 134168)
@@ -333,6 +333,8 @@
         }
         
         void haveABadTime(JSGlobalData&);
+        
+        bool arrayPrototypeChainIsSane();
 
         void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; }
         unsigned profileGroup() const
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to