Title: [134151] trunk/Source/_javascript_Core
Revision
134151
Author
fpi...@apple.com
Date
2012-11-09 21:54:11 -0800 (Fri, 09 Nov 2012)

Log Message

If the DFG ArrayMode says that an access is on an OriginalArray, then the checks should always enforce this
https://bugs.webkit.org/show_bug.cgi?id=101720

Reviewed by Mark Hahnenberg.

Previously, "original" arrays was just a hint that we could find the structure
of the array if we needed to even if the array profile didn't have it due to
polymorphism. Now, "original" arrays are a property that is actually checked:
if an array access has ArrayMode::arrayClass() == Array::OriginalArray, then we
can be sure that the code performing the access is dealing with not just a
JSArray, but a JSArray that has no named properties, no indexed accessors, and
the ArrayPrototype as its prototype. This will be useful for optimizations that
are being done as part of https://bugs.webkit.org/show_bug.cgi?id=101720.

* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGArrayMode.cpp:
(JSC::DFG::ArrayMode::originalArrayStructure):
(DFG):
(JSC::DFG::ArrayMode::alreadyChecked):
* dfg/DFGArrayMode.h:
(JSC):
(DFG):
(JSC::DFG::ArrayMode::withProfile):
(ArrayMode):
(JSC::DFG::ArrayMode::benefitsFromOriginalArray):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::checkArray):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode):
(JSC::DFG::SpeculativeJIT::checkArray):
(JSC::DFG::SpeculativeJIT::compileGetByValOnString):
(JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray):
(JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray):
(JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray):
(JSC::DFG::SpeculativeJIT::compileGetByValOnArguments):
(JSC::DFG::SpeculativeJIT::compileGetArgumentsLength):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (134150 => 134151)


--- trunk/Source/_javascript_Core/ChangeLog	2012-11-10 05:16:00 UTC (rev 134150)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-11-10 05:54:11 UTC (rev 134151)
@@ -1,5 +1,47 @@
 2012-11-09  Filip Pizlo  <fpi...@apple.com>
 
+        If the DFG ArrayMode says that an access is on an OriginalArray, then the checks should always enforce this
+        https://bugs.webkit.org/show_bug.cgi?id=101720
+
+        Reviewed by Mark Hahnenberg.
+
+        Previously, "original" arrays was just a hint that we could find the structure
+        of the array if we needed to even if the array profile didn't have it due to
+        polymorphism. Now, "original" arrays are a property that is actually checked:
+        if an array access has ArrayMode::arrayClass() == Array::OriginalArray, then we
+        can be sure that the code performing the access is dealing with not just a
+        JSArray, but a JSArray that has no named properties, no indexed accessors, and
+        the ArrayPrototype as its prototype. This will be useful for optimizations that
+        are being done as part of https://bugs.webkit.org/show_bug.cgi?id=101720.
+
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGArrayMode.cpp:
+        (JSC::DFG::ArrayMode::originalArrayStructure):
+        (DFG):
+        (JSC::DFG::ArrayMode::alreadyChecked):
+        * dfg/DFGArrayMode.h:
+        (JSC):
+        (DFG):
+        (JSC::DFG::ArrayMode::withProfile):
+        (ArrayMode):
+        (JSC::DFG::ArrayMode::benefitsFromOriginalArray):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::checkArray):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode):
+        (JSC::DFG::SpeculativeJIT::checkArray):
+        (JSC::DFG::SpeculativeJIT::compileGetByValOnString):
+        (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray):
+        (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray):
+        (JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray):
+        (JSC::DFG::SpeculativeJIT::compileGetByValOnArguments):
+        (JSC::DFG::SpeculativeJIT::compileGetArgumentsLength):
+
+2012-11-09  Filip Pizlo  <fpi...@apple.com>
+
         Fix indentation of BooleanPrototype.h
 
         Rubber stamped by Mark Hahnenberg.

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (134150 => 134151)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-11-10 05:16:00 UTC (rev 134150)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-11-10 05:54:11 UTC (rev 134151)
@@ -1452,7 +1452,7 @@
         forNode(nodeIndex).clear(); // The result is not a JS value.
         break;
     case CheckArray: {
-        if (node.arrayMode().alreadyChecked(forNode(node.child1()))) {
+        if (node.arrayMode().alreadyChecked(m_graph, node, forNode(node.child1()))) {
             m_foundConstants = true;
             node.setCanExit(false);
             break;
@@ -1508,7 +1508,7 @@
         break;
     }
     case Arrayify: {
-        if (node.arrayMode().alreadyChecked(forNode(node.child1()))) {
+        if (node.arrayMode().alreadyChecked(m_graph, node, forNode(node.child1()))) {
             m_foundConstants = true;
             node.setCanExit(false);
             break;

Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp (134150 => 134151)


--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2012-11-10 05:16:00 UTC (rev 134150)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.cpp	2012-11-10 05:54:11 UTC (rev 134151)
@@ -29,6 +29,7 @@
 #if ENABLE(DFG_JIT)
 
 #include "DFGAbstractValue.h"
+#include "DFGGraph.h"
 
 namespace JSC { namespace DFG {
 
@@ -200,22 +201,58 @@
     }
 }
 
-bool ArrayMode::alreadyChecked(AbstractValue& value, IndexingType shape) const
+Structure* ArrayMode::originalArrayStructure(Graph& graph, const CodeOrigin& codeOrigin) const
 {
-    if (isJSArray()) {
+    if (!isJSArrayWithOriginalStructure())
+        return 0;
+    
+    JSGlobalObject* globalObject = graph.globalObjectFor(codeOrigin);
+    
+    switch (type()) {
+    case Array::Int32:
+        return globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
+    case Array::Double:
+        return globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
+    case Array::Contiguous:
+        return globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
+    case Array::ArrayStorage:
+        return globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
+    default:
+        CRASH();
+        return 0;
+    }
+}
+
+Structure* ArrayMode::originalArrayStructure(Graph& graph, Node& node) const
+{
+    return originalArrayStructure(graph, node.codeOrigin);
+}
+
+bool ArrayMode::alreadyChecked(Graph& graph, Node& node, AbstractValue& value, IndexingType shape) const
+{
+    switch (arrayClass()) {
+    case Array::OriginalArray:
+        return value.m_currentKnownStructure.hasSingleton()
+            && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape
+            && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray)
+            && graph.globalObjectFor(node.codeOrigin)->isOriginalArrayStructure(value.m_currentKnownStructure.singleton());
+        
+    case Array::Array:
         if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape | IsArray)))
             return true;
         return value.m_currentKnownStructure.hasSingleton()
             && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape
             && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+        
+    default:
+        if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray)))
+            return true;
+        return value.m_currentKnownStructure.hasSingleton()
+            && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape;
     }
-    if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray)))
-        return true;
-    return value.m_currentKnownStructure.hasSingleton()
-        && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape;
 }
 
-bool ArrayMode::alreadyChecked(AbstractValue& value) const
+bool ArrayMode::alreadyChecked(Graph& graph, Node& node, AbstractValue& value) const
 {
     switch (type()) {
     case Array::Generic:
@@ -228,29 +265,36 @@
         return speculationChecked(value.m_type, SpecString);
         
     case Array::Int32:
-        return alreadyChecked(value, Int32Shape);
+        return alreadyChecked(graph, node, value, Int32Shape);
         
     case Array::Double:
-        return alreadyChecked(value, DoubleShape);
+        return alreadyChecked(graph, node, value, DoubleShape);
         
     case Array::Contiguous:
-        return alreadyChecked(value, ContiguousShape);
+        return alreadyChecked(graph, node, value, ContiguousShape);
         
     case Array::ArrayStorage:
-        return alreadyChecked(value, ArrayStorageShape);
+        return alreadyChecked(graph, node, value, ArrayStorageShape);
         
     case Array::SlowPutArrayStorage:
-        if (isJSArray()) {
+        switch (arrayClass()) {
+        case Array::OriginalArray:
+            CRASH();
+            return false;
+        
+        case Array::Array:
             if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
                 return true;
             return value.m_currentKnownStructure.hasSingleton()
                 && hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
                 && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+        
+        default:
+            if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
+                return true;
+            return value.m_currentKnownStructure.hasSingleton()
+                && hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
         }
-        if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
-            return true;
-        return value.m_currentKnownStructure.hasSingleton()
-            && hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
         
     case Array::Arguments:
         return speculationChecked(value.m_type, SpecArguments);

Modified: trunk/Source/_javascript_Core/dfg/DFGArrayMode.h (134150 => 134151)


--- trunk/Source/_javascript_Core/dfg/DFGArrayMode.h	2012-11-10 05:16:00 UTC (rev 134150)
+++ trunk/Source/_javascript_Core/dfg/DFGArrayMode.h	2012-11-10 05:54:11 UTC (rev 134151)
@@ -33,9 +33,15 @@
 #include "ArrayProfile.h"
 #include "SpeculatedType.h"
 
-namespace JSC { namespace DFG {
+namespace JSC {
 
+struct CodeOrigin;
+
+namespace DFG {
+
+class Graph;
 struct AbstractValue;
+struct Node;
 
 // Use a namespace + enum instead of enum alone to avoid the namespace collision
 // that would otherwise occur, since we say things like "Int8Array" and "JSArray"
@@ -161,7 +167,7 @@
             mySpeculation = Array::InBounds;
         
         if (isJSArray()) {
-            if (profile->usesOriginalArrayStructures())
+            if (profile->usesOriginalArrayStructures() && benefitsFromOriginalArray())
                 myArrayClass = Array::OriginalArray;
             else
                 myArrayClass = Array::Array;
@@ -183,7 +189,7 @@
     
     ArrayMode refine(SpeculatedType base, SpeculatedType index, SpeculatedType value = SpecNone) const;
     
-    bool alreadyChecked(AbstractValue&) const;
+    bool alreadyChecked(Graph&, Node&, AbstractValue&) const;
     
     const char* toString() const;
     
@@ -303,6 +309,23 @@
         }
     }
     
+    bool benefitsFromOriginalArray() const
+    {
+        switch (type()) {
+        case Array::Int32:
+        case Array::Double:
+        case Array::Contiguous:
+        case Array::ArrayStorage:
+            return true;
+        default:
+            return false;
+        }
+    }
+    
+    // Returns 0 if this is not OriginalArray.
+    Structure* originalArrayStructure(Graph&, const CodeOrigin&) const;
+    Structure* originalArrayStructure(Graph&, Node&) const;
+    
     bool benefitsFromStructureCheck() const
     {
         switch (type()) {
@@ -375,7 +398,7 @@
         }
     }
     
-    bool alreadyChecked(AbstractValue&, IndexingType shape) const;
+    bool alreadyChecked(Graph&, Node&, AbstractValue&, IndexingType shape) const;
     
     union {
         struct {

Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (134150 => 134151)


--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2012-11-10 05:16:00 UTC (rev 134150)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2012-11-10 05:54:11 UTC (rev 134151)
@@ -116,7 +116,7 @@
                 
             case CheckArray:
             case Arrayify: {
-                if (!node.arrayMode().alreadyChecked(m_state.forNode(node.child1())))
+                if (!node.arrayMode().alreadyChecked(m_graph, node, m_state.forNode(node.child1())))
                     break;
                 ASSERT(node.refCount() == 1);
                 node.setOpAndDefaultFlags(Phantom);

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (134150 => 134151)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2012-11-10 05:16:00 UTC (rev 134150)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2012-11-10 05:54:11 UTC (rev 134151)
@@ -424,31 +424,12 @@
         
         m_graph.ref(array);
 
+        Structure* structure = arrayMode.originalArrayStructure(m_graph, codeOrigin);
+        
         if (arrayMode.doesConversion()) {
             if (index != NoNode)
                 m_graph.ref(index);
             
-            Structure* structure = 0;
-            if (arrayMode.isJSArrayWithOriginalStructure()) {
-                JSGlobalObject* globalObject = m_graph.baselineCodeBlockFor(codeOrigin)->globalObject();
-                switch (arrayMode.type()) {
-                case Array::Int32:
-                    structure = globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
-                    break;
-                case Array::Double:
-                    structure = globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
-                    break;
-                case Array::Contiguous:
-                    structure = globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
-                    break;
-                case Array::ArrayStorage:
-                    structure = globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
-                    break;
-                default:
-                    break;
-                }
-            }
-            
             if (structure) {
                 Node arrayify(ArrayifyToStructure, codeOrigin, OpInfo(structure), OpInfo(arrayMode.asWord()), array, index);
                 arrayify.ref();
@@ -463,11 +444,19 @@
                 m_insertionSet.append(m_indexInBlock, arrayifyIndex);
             }
         } else {
-            Node checkArray(CheckArray, codeOrigin, OpInfo(arrayMode.asWord()), array);
-            checkArray.ref();
-            NodeIndex checkArrayIndex = m_graph.size();
-            m_graph.append(checkArray);
-            m_insertionSet.append(m_indexInBlock, checkArrayIndex);
+            if (structure) {
+                Node checkStructure(CheckStructure, codeOrigin, OpInfo(m_graph.addStructureSet(structure)), array);
+                checkStructure.ref();
+                NodeIndex checkStructureIndex = m_graph.size();
+                m_graph.append(checkStructure);
+                m_insertionSet.append(m_indexInBlock, checkStructureIndex);
+            } else {
+                Node checkArray(CheckArray, codeOrigin, OpInfo(arrayMode.asWord()), array);
+                checkArray.ref();
+                NodeIndex checkArrayIndex = m_graph.size();
+                m_graph.append(checkArray);
+                m_insertionSet.append(m_indexInBlock, checkArrayIndex);
+            }
         }
         
         if (!storageCheck(arrayMode))

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (134150 => 134151)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2012-11-10 05:16:00 UTC (rev 134150)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2012-11-10 05:54:11 UTC (rev 134151)
@@ -361,13 +361,22 @@
 
 JITCompiler::Jump SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, IndexingType shape, bool invert)
 {
-    if (arrayMode.isJSArray()) {
+    switch (arrayMode.arrayClass()) {
+    case Array::OriginalArray: {
+        CRASH();
+        JITCompiler::Jump result; // I already know that VC++ takes unkindly to the _expression_ "return Jump()", so I'm doing it this way in anticipation of someone eventually using VC++ to compile the DFG.
+        return result;
+    }
+        
+    case Array::Array:
         m_jit.and32(TrustedImm32(IsArray | IndexingShapeMask), tempGPR);
         return m_jit.branch32(
             invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(IsArray | shape));
+        
+    default:
+        m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
+        return m_jit.branch32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape));
     }
-    m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
-    return m_jit.branch32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, tempGPR, TrustedImm32(shape));
 }
 
 JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGPR, ArrayMode arrayMode, bool invert)
@@ -386,12 +395,13 @@
 
     case Array::ArrayStorage:
     case Array::SlowPutArrayStorage: {
+        ASSERT(!arrayMode.isJSArrayWithOriginalStructure());
+        
         if (arrayMode.isJSArray()) {
             if (arrayMode.isSlowPut()) {
                 if (invert) {
-                    JITCompiler::Jump slow = 
-                        m_jit.branchTest32(
-                            MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray));
+                    JITCompiler::Jump slow = m_jit.branchTest32(
+                        MacroAssembler::Zero, tempGPR, MacroAssembler::TrustedImm32(IsArray));
                     m_jit.and32(TrustedImm32(IndexingShapeMask), tempGPR);
                     m_jit.sub32(TrustedImm32(ArrayStorageShape), tempGPR);
                     result.append(
@@ -449,7 +459,7 @@
     
     const TypedArrayDescriptor* result = typedArrayDescriptor(node.arrayMode());
     
-    if (node.arrayMode().alreadyChecked(m_state.forNode(node.child1()))) {
+    if (node.arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1()))) {
         noResult(m_compileIndex);
         return;
     }
@@ -1959,7 +1969,7 @@
     GPRReg propertyReg = property.gpr();
     GPRReg storageReg = storage.gpr();
 
-    ASSERT(ArrayMode(Array::String).alreadyChecked(m_state.forNode(node.child1())));
+    ASSERT(ArrayMode(Array::String).alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
 
     // unsigned comparison so we can filter out negative indices and indices that are too large
     speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSString::offsetOfLength())));
@@ -2368,7 +2378,7 @@
     GPRTemporary result(this);
     GPRReg resultReg = result.gpr();
 
-    ASSERT(node.arrayMode().alreadyChecked(m_state.forNode(node.child1())));
+    ASSERT(node.arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
 
     speculationCheck(
         Uncountable, JSValueRegs(), NoNode,
@@ -2518,7 +2528,7 @@
     GPRReg propertyReg = property.gpr();
     GPRReg storageReg = storage.gpr();
 
-    ASSERT(node.arrayMode().alreadyChecked(m_state.forNode(node.child1())));
+    ASSERT(node.arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
 
     FPRTemporary result(this);
     FPRReg resultReg = result.fpr();
@@ -2555,7 +2565,7 @@
     
     SpeculateDoubleOperand valueOp(this, valueUse);
     
-    ASSERT_UNUSED(baseUse, node.arrayMode().alreadyChecked(m_state.forNode(baseUse)));
+    ASSERT_UNUSED(baseUse, node.arrayMode().alreadyChecked(m_jit.graph(), m_jit.graph()[m_compileIndex], m_state.forNode(baseUse)));
     
     GPRTemporary result(this);
     
@@ -3378,7 +3388,7 @@
     if (!m_compileOkay)
         return;
   
-    ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_state.forNode(node.child1())));
+    ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
     
     // Two really lame checks.
     speculationCheck(
@@ -3435,7 +3445,7 @@
     if (!m_compileOkay)
         return;
     
-    ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_state.forNode(node.child1())));
+    ASSERT(ArrayMode(Array::Arguments).alreadyChecked(m_jit.graph(), node, m_state.forNode(node.child1())));
     
     speculationCheck(
         Uncountable, JSValueSource(), NoNode,
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to