Title: [147286] branches/dfgFourthTier/Source/_javascript_Core
Revision
147286
Author
[email protected]
Date
2013-03-31 12:33:53 -0700 (Sun, 31 Mar 2013)

Log Message

fourthTier: FTL JIT should be able to compile the Array.prototype.findGraphNode function in Kraken/ai-astar
https://bugs.webkit.org/show_bug.cgi?id=113646

Reviewed by Oliver Hunt.
        
This adds enough FTL support to compile Array.prototype.findGraphNode. This isn't
a speed-up, yet, because findGraphNode tends to be aggressively inlined by the DFG,
and the FTL can't yet compile the things into which it was inlined. In future
patches we will get to a point where we can compile the callers, and then we'll be
able to see what the performance effects are.
        
But the interesting thing is that it isn't a slow-down, either. This implies that
even if we FTL compile a CodeBlock that we shouldn't have (the fact that we
compiling things that end up being inlined is dumb, and the fact that the current
FTL tiering strategy launches LLVM for those things is even dumber), we still run
at OK performance.

* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::transferAndCheckArguments):
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileCheckStructure):
(LowerDFGToLLVM):
(JSC::FTL::LowerDFGToLLVM::compileGetButterfly):
(JSC::FTL::LowerDFGToLLVM::compileGetArrayLength):
(JSC::FTL::LowerDFGToLLVM::compileGetByVal):
(JSC::FTL::LowerDFGToLLVM::compileGetByOffset):
(JSC::FTL::LowerDFGToLLVM::compileCompareEq):
(JSC::FTL::LowerDFGToLLVM::lowInt32):
(JSC::FTL::LowerDFGToLLVM::lowCell):
(JSC::FTL::LowerDFGToLLVM::lowObject):
(JSC::FTL::LowerDFGToLLVM::lowBoolean):
(JSC::FTL::LowerDFGToLLVM::lowJSValue):
(JSC::FTL::LowerDFGToLLVM::lowStorage):
(JSC::FTL::LowerDFGToLLVM::isNotInt32):
(JSC::FTL::LowerDFGToLLVM::isNotCell):
(JSC::FTL::LowerDFGToLLVM::isNotBoolean):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateCell):
(JSC::FTL::LowerDFGToLLVM::speculateObject):
(JSC::FTL::LowerDFGToLLVM::accountedPointer):
(JSC::FTL::LowerDFGToLLVM::weakPointer):
* ftl/FTLOutput.h:
(JSC::FTL::Output::Output):
(JSC::FTL::Output::insertNewBlocksBefore):
(JSC::FTL::Output::appendTo):
(Output):
(JSC::FTL::Output::baseIndex):

Modified Paths

Diff

Modified: branches/dfgFourthTier/Source/_javascript_Core/ChangeLog (147285 => 147286)


--- branches/dfgFourthTier/Source/_javascript_Core/ChangeLog	2013-03-31 04:30:59 UTC (rev 147285)
+++ branches/dfgFourthTier/Source/_javascript_Core/ChangeLog	2013-03-31 19:33:53 UTC (rev 147286)
@@ -1,3 +1,55 @@
+2013-03-30  Filip Pizlo  <[email protected]>
+
+        fourthTier: FTL JIT should be able to compile the Array.prototype.findGraphNode function in Kraken/ai-astar
+        https://bugs.webkit.org/show_bug.cgi?id=113646
+
+        Reviewed by Oliver Hunt.
+        
+        This adds enough FTL support to compile Array.prototype.findGraphNode. This isn't
+        a speed-up, yet, because findGraphNode tends to be aggressively inlined by the DFG,
+        and the FTL can't yet compile the things into which it was inlined. In future
+        patches we will get to a point where we can compile the callers, and then we'll be
+        able to see what the performance effects are.
+        
+        But the interesting thing is that it isn't a slow-down, either. This implies that
+        even if we FTL compile a CodeBlock that we shouldn't have (the fact that we
+        compiling things that end up being inlined is dumb, and the fact that the current
+        FTL tiering strategy launches LLVM for those things is even dumber), we still run
+        at OK performance.
+
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::transferAndCheckArguments):
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileCheckStructure):
+        (LowerDFGToLLVM):
+        (JSC::FTL::LowerDFGToLLVM::compileGetButterfly):
+        (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength):
+        (JSC::FTL::LowerDFGToLLVM::compileGetByVal):
+        (JSC::FTL::LowerDFGToLLVM::compileGetByOffset):
+        (JSC::FTL::LowerDFGToLLVM::compileCompareEq):
+        (JSC::FTL::LowerDFGToLLVM::lowInt32):
+        (JSC::FTL::LowerDFGToLLVM::lowCell):
+        (JSC::FTL::LowerDFGToLLVM::lowObject):
+        (JSC::FTL::LowerDFGToLLVM::lowBoolean):
+        (JSC::FTL::LowerDFGToLLVM::lowJSValue):
+        (JSC::FTL::LowerDFGToLLVM::lowStorage):
+        (JSC::FTL::LowerDFGToLLVM::isNotInt32):
+        (JSC::FTL::LowerDFGToLLVM::isNotCell):
+        (JSC::FTL::LowerDFGToLLVM::isNotBoolean):
+        (JSC::FTL::LowerDFGToLLVM::speculate):
+        (JSC::FTL::LowerDFGToLLVM::speculateCell):
+        (JSC::FTL::LowerDFGToLLVM::speculateObject):
+        (JSC::FTL::LowerDFGToLLVM::accountedPointer):
+        (JSC::FTL::LowerDFGToLLVM::weakPointer):
+        * ftl/FTLOutput.h:
+        (JSC::FTL::Output::Output):
+        (JSC::FTL::Output::insertNewBlocksBefore):
+        (JSC::FTL::Output::appendTo):
+        (Output):
+        (JSC::FTL::Output::baseIndex):
+
 2013-03-29  Filip Pizlo  <[email protected]>
 
         fourthTier: FTL JIT should be able to compile the Marsaglia random number generator

Modified: branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLCapabilities.cpp (147285 => 147286)


--- branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2013-03-31 04:30:59 UTC (rev 147285)
+++ branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2013-03-31 19:33:53 UTC (rev 147286)
@@ -51,6 +51,9 @@
                 case Int32Use:
                 case KnownInt32Use:
                 case BooleanUse:
+                case CellUse:
+                case KnownCellUse:
+                case ObjectUse:
                     // These are OK.
                     break;
                 default:
@@ -75,6 +78,9 @@
             case BitOr:
             case BitRShift:
             case BitLShift:
+            case CheckStructure:
+            case GetButterfly:
+            case GetByOffset:
                 // These are OK.
                 break;
             case ValueAdd:
@@ -83,6 +89,37 @@
                 if (node->binaryUseKind() == Int32Use)
                     break;
                 return false;
+            case GetArrayLength:
+                switch (node->arrayMode().type()) {
+                case Array::Int32:
+                case Array::Double:
+                case Array::Contiguous:
+                    break;
+                default:
+                    return false;
+                }
+                break;
+            case GetByVal:
+                switch (node->arrayMode().type()) {
+                case Array::Contiguous:
+                    break;
+                default:
+                    return false;
+                }
+                switch (node->arrayMode().speculation()) {
+                case Array::SaneChain:
+                case Array::InBounds:
+                    break;
+                default:
+                    return false;
+                }
+                break;
+            case CompareEq:
+                if (node->isBinaryUseKind(Int32Use))
+                    break;
+                if (node->isBinaryUseKind(ObjectUse))
+                    break;
+                return false;
             case CompareLess:
                 if (node->isBinaryUseKind(Int32Use))
                     break;

Modified: branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (147285 => 147286)


--- branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2013-03-31 04:30:59 UTC (rev 147285)
+++ branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2013-03-31 19:33:53 UTC (rev 147286)
@@ -171,18 +171,18 @@
                 SpeculatedType prediction = variable->prediction();
                 
                 if (isInt32Speculation(prediction)) {
-                    speculateBackward(BadType, jsValue, node, checkNotInt32(jsValue));
+                    speculateBackward(BadType, jsValue, node, isNotInt32(jsValue));
                     m_out.set(unboxInt32(jsValue), m_locals32.operand(variable->local()));
                     continue;
                 }
                 
                 if (isCellSpeculation(prediction)) {
-                    speculateBackward(BadType, jsValue, node, checkNotCell(jsValue));
+                    speculateBackward(BadType, jsValue, node, isNotCell(jsValue));
                     m_out.set(jsValue, m_locals64.operand(variable->local()));
                     continue;
                 }
                 if (isBooleanSpeculation(prediction)) {
-                    speculateBackward(BadType, jsValue, node, checkNotBoolean(jsValue));
+                    speculateBackward(BadType, jsValue, node, isNotBoolean(jsValue));
                     m_out.set(unboxBoolean(jsValue), m_localsBoolean.operand(variable->local()));
                     continue;
                 }
@@ -285,6 +285,24 @@
         case BitLShift:
             compileBitLShift();
             break;
+        case CheckStructure:
+            compileCheckStructure();
+            break;
+        case GetButterfly:
+            compileGetButterfly();
+            break;
+        case GetArrayLength:
+            compileGetArrayLength();
+            break;
+        case GetByVal:
+            compileGetByVal();
+            break;
+        case GetByOffset:
+            compileGetByOffset();
+            break;
+        case CompareEq:
+            compileCompareEq();
+            break;
         case CompareLess:
             compileCompareLess();
             break;
@@ -517,6 +535,127 @@
                 m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
     }
     
+    void compileCheckStructure()
+    {
+        LValue cell = lowCell(m_node->child1());
+        
+        ExitKind exitKind;
+        if (m_node->child1()->op() == WeakJSConstant)
+            exitKind = BadWeakConstantCache;
+        else
+            exitKind = BadCache;
+        
+        LValue structure = m_out.loadPtr(cell, JSCell::structureOffset());
+        
+        if (m_node->structureSet().size() == 1) {
+            speculate(
+                exitKind, cell, 0,
+                m_out.notEqual(structure, weakPointer(m_node->structureSet()[0])));
+            return;
+        }
+        
+        LBasicBlock continuation = m_out.newBlock();
+        
+        LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation);
+        for (unsigned i = 0; i < m_node->structureSet().size() - 1; ++i) {
+            LBasicBlock nextStructure = m_out.newBlock();
+            m_out.branch(
+                m_out.equal(structure, weakPointer(m_node->structureSet()[i])),
+                continuation, nextStructure);
+            m_out.appendTo(nextStructure);
+        }
+        
+        speculate(
+            exitKind, cell, 0,
+            m_out.notEqual(structure, weakPointer(m_node->structureSet().last())));
+        
+        m_out.appendTo(continuation, lastNext);
+    }
+    
+    void compileGetButterfly()
+    {
+        m_storageValues.add(
+            m_node, m_out.loadPtr(lowCell(m_node->child1()), JSObject::butterflyOffset()));
+    }
+    
+    void compileGetArrayLength()
+    {
+        switch (m_node->arrayMode().type()) {
+        case Array::Int32:
+        case Array::Double:
+        case Array::Contiguous: {
+            m_int32Values.add(
+                m_node, m_out.load32(lowStorage(m_node->child2()), Butterfly::offsetOfPublicLength()));
+            break;
+        }
+            
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+    
+    void compileGetByVal()
+    {
+        LValue index = lowInt32(m_node->child2());
+        LValue storage = lowStorage(m_node->child3());
+        
+        switch (m_node->arrayMode().type()) {
+        case Array::Contiguous: {
+            if (m_node->arrayMode().isInBounds()) {
+                speculate(
+                    OutOfBounds, 0, 0,
+                    m_out.aboveOrEqual(
+                        index, m_out.load32(storage, Butterfly::offsetOfPublicLength())));
+                
+                LValue result = m_out.load64(
+                    m_out.baseIndex(storage, m_out.zeroExt(index, m_out.intPtr), ScaleEight));
+                speculate(LoadFromHole, 0, 0, m_out.isZero64(result));
+                m_jsValueValues.add(m_node, result);
+                break;
+            }
+            
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+            
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+    
+    void compileGetByOffset()
+    {
+        StorageAccessData& storageAccessData =
+            m_graph.m_storageAccessData[m_node->storageAccessDataIndex()];
+        
+        m_jsValueValues.add(
+            m_node,
+            m_out.load64(
+                lowStorage(m_node->child1()),
+                storageAccessData.offset * sizeof(EncodedJSValue)));
+    }
+    
+    void compileCompareEq()
+    {
+        if (m_node->isBinaryUseKind(Int32Use)) {
+            m_booleanValues.add(
+                m_node,
+                m_out.equal(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
+            return;
+        }
+        
+        if (m_node->isBinaryUseKind(ObjectUse)) {
+            m_booleanValues.add(
+                m_node,
+                m_out.equal(lowObject(m_node->child1()), lowObject(m_node->child2())));
+            return;
+        }
+        
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    
     void compileCompareLess()
     {
         if (m_node->isBinaryUseKind(Int32Use)) {
@@ -610,7 +749,7 @@
             return result;
         
         if (LValue boxedResult = m_jsValueValues.get(edge.node())) {
-            FTL_TYPE_CHECK(boxedResult, edge, SpecInt32, checkNotInt32(boxedResult));
+            FTL_TYPE_CHECK(boxedResult, edge, SpecInt32, isNotInt32(boxedResult));
             LValue result = unboxInt32(boxedResult);
             m_int32Values.add(edge.node(), result);
             return result;
@@ -626,7 +765,7 @@
         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || isCell(edge.useKind()));
         
         if (LValue uncheckedResult = m_jsValueValues.get(edge.node())) {
-            FTL_TYPE_CHECK(uncheckedResult, edge, SpecCell, checkNotCell(uncheckedResult));
+            FTL_TYPE_CHECK(uncheckedResult, edge, SpecCell, isNotCell(uncheckedResult));
             return uncheckedResult;
         }
         
@@ -635,6 +774,15 @@
         return m_out.intPtrZero;
     }
     
+    LValue lowObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+    {
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
+        
+        LValue result = lowCell(edge, mode);
+        speculateObject(edge, result);
+        return result;
+    }
+    
     LValue lowBoolean(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
     {
         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BooleanUse);
@@ -643,8 +791,10 @@
             return result;
         
         if (LValue unboxedResult = m_jsValueValues.get(edge.node())) {
-            FTL_TYPE_CHECK(unboxedResult, edge, SpecBoolean, checkNotBoolean(unboxedResult));
-            return unboxBoolean(unboxedResult);
+            FTL_TYPE_CHECK(unboxedResult, edge, SpecBoolean, isNotBoolean(unboxedResult));
+            LValue result = unboxBoolean(unboxedResult);
+            m_booleanValues.add(edge.node(), result);
+            return result;
         }
         
         RELEASE_ASSERT(!(m_state.forNode(edge).m_type & SpecBoolean));
@@ -659,18 +809,34 @@
         if (LValue result = m_jsValueValues.get(edge.node()))
             return result;
         
-        if (LValue unboxedResult = m_int32Values.get(edge.node()))
-            return boxInt32(unboxedResult);
+        if (LValue unboxedResult = m_int32Values.get(edge.node())) {
+            LValue result = boxInt32(unboxedResult);
+            m_jsValueValues.add(edge.node(), result);
+            return result;
+        }
         
-        if (LValue unboxedResult = m_booleanValues.get(edge.node()))
-            return boxBoolean(unboxedResult);
+        if (LValue unboxedResult = m_booleanValues.get(edge.node())) {
+            LValue result = boxBoolean(unboxedResult);
+            m_jsValueValues.add(edge.node(), result);
+            return result;
+        }
         
         RELEASE_ASSERT_NOT_REACHED();
         return 0;
     }
     
-    LValue checkNotInt32(LValue jsValue)
+    LValue lowStorage(Edge edge)
     {
+        if (LValue result = m_storageValues.get(edge.node()))
+            return result;
+        
+        LValue result = lowCell(edge);
+        m_storageValues.add(edge.node(), result);
+        return result;
+    }
+    
+    LValue isNotInt32(LValue jsValue)
+    {
         return m_out.below(jsValue, m_tagTypeNumber);
     }
     LValue unboxInt32(LValue jsValue)
@@ -682,12 +848,12 @@
         return m_out.add(m_out.zeroExt(value, m_out.int64), m_tagTypeNumber);
     }
     
-    LValue checkNotCell(LValue jsValue)
+    LValue isNotCell(LValue jsValue)
     {
         return m_out.testNonZero64(jsValue, m_tagMask);
     }
     
-    LValue checkNotBoolean(LValue jsValue)
+    LValue isNotBoolean(LValue jsValue)
     {
         return m_out.testNonZero64(
             m_out.bitXor(jsValue, m_out.constInt64(ValueFalse)),
@@ -716,6 +882,15 @@
         case Int32Use:
             speculateInt32(edge);
             break;
+        case CellUse:
+            speculateCell(edge);
+            break;
+        case KnownCellUse:
+            ASSERT(!m_state.needsTypeCheck(edge));
+            break;
+        case ObjectUse:
+            speculateObject(edge);
+            break;
         default:
             RELEASE_ASSERT_NOT_REACHED();
         }
@@ -731,6 +906,36 @@
         lowInt32(edge);
     }
     
+    void speculateCell(Edge edge)
+    {
+        lowCell(edge);
+    }
+    
+    void speculateObject(Edge edge, LValue cell)
+    {
+        FTL_TYPE_CHECK(
+            cell, edge, SpecObject,
+            m_out.equal(
+                m_out.loadPtr(cell, JSCell::structureOffset()),
+                accountedPointer(globalData().structureStructure.get())));
+    }
+    
+    void speculateObject(Edge edge)
+    {
+        speculateObject(edge, lowCell(edge));
+    }
+    
+    LValue accountedPointer(JSCell* pointer)
+    {
+        return m_out.constIntPtr(bitwise_cast<intptr_t>(pointer));
+    }
+    
+    LValue weakPointer(JSCell* pointer)
+    {
+        codeBlock()->appendWeakReference(pointer);
+        return accountedPointer(pointer);
+    }
+    
     LValue addressFor(LValue base, int operand)
     {
         return m_out.add(base, m_out.constIntPtr(operand * sizeof(Register)));

Modified: branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLOutput.h (147285 => 147286)


--- branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLOutput.h	2013-03-31 04:30:59 UTC (rev 147285)
+++ branches/dfgFourthTier/Source/_javascript_Core/ftl/FTLOutput.h	2013-03-31 19:33:53 UTC (rev 147286)
@@ -51,6 +51,8 @@
 // These translate the pointer + offset into a reference (or, a pointer in LLVM-speak)
 // and use get and set on them (or, load and store in LLVM-speak).
 
+enum Scale { ScaleOne, ScaleTwo, ScaleFour, ScaleEight, ScalePtr };
+
 class Output {
 public:
     Output()
@@ -67,6 +69,12 @@
         , int32Zero(constInt(int32, 0, SignExtend))
         , int64Zero(constInt(int64, 0, SignExtend))
         , intPtrZero(constInt(intPtr, 0, SignExtend))
+        , intPtrOne(constInt(intPtr, 1, SignExtend))
+        , intPtrTwo(constInt(intPtr, 2, SignExtend))
+        , intPtrThree(constInt(intPtr, 3, SignExtend))
+        , intPtrFour(constInt(intPtr, 4, SignExtend))
+        , intPtrEight(constInt(intPtr, 8, SignExtend))
+        , intPtrPtr(constInt(intPtr, sizeof(void*), SignExtend))
         , m_function(0)
         , m_builder(LLVMCreateBuilder())
         , m_block(0)
@@ -87,15 +95,19 @@
         m_function = function;
     }
     
-    LBasicBlock appendTo(LBasicBlock block, LBasicBlock nextBlock)
+    LBasicBlock insertNewBlocksBefore(LBasicBlock nextBlock)
     {
         LBasicBlock lastNextBlock = m_nextBlock;
         m_nextBlock = nextBlock;
-        
-        appendTo(block);
         return lastNextBlock;
     }
     
+    LBasicBlock appendTo(LBasicBlock block, LBasicBlock nextBlock)
+    {
+        appendTo(block);
+        return insertNewBlocksBefore(nextBlock);
+    }
+    
     void appendTo(LBasicBlock block)
     {
         m_block = block;
@@ -154,6 +166,32 @@
     void store64(LValue value, LValue pointer, ptrdiff_t offset = 0) { store(value, pointer, offset, ref64); }
     void storePtr(LValue value, LValue pointer, ptrdiff_t offset = 0) { store(value, pointer, offset, refPtr); }
     
+    LValue baseIndex(LValue base, LValue index, Scale scale, ptrdiff_t offset = 0)
+    {
+        LValue accumulatedOffset;
+        
+        switch (scale) {
+        case ScaleOne:
+            accumulatedOffset = index;
+            break;
+        case ScaleTwo:
+            accumulatedOffset = shl(index, intPtrOne);
+            break;
+        case ScaleFour:
+            accumulatedOffset = shl(index, intPtrTwo);
+            break;
+        case ScaleEight:
+        case ScalePtr:
+            accumulatedOffset = shl(index, intPtrThree);
+            break;
+        }
+        
+        if (offset)
+            accumulatedOffset = add(accumulatedOffset, constIntPtr(offset));
+        
+        return add(base, accumulatedOffset);
+    }
+    
     LValue equal(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntEQ, left, right); }
     LValue notEqual(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntNE, left, right); }
     LValue above(LValue left, LValue right) { return buildICmp(m_builder, LLVMIntUGT, left, right); }
@@ -218,6 +256,12 @@
     const LValue int32Zero;
     const LValue int64Zero;
     const LValue intPtrZero;
+    const LValue intPtrOne;
+    const LValue intPtrTwo;
+    const LValue intPtrThree;
+    const LValue intPtrFour;
+    const LValue intPtrEight;
+    const LValue intPtrPtr;
     
     LModule m_module;
     LValue m_function;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to