Title: [97030] trunk/Source/_javascript_Core
Revision
97030
Author
fpi...@apple.com
Date
2011-10-09 13:07:36 -0700 (Sun, 09 Oct 2011)

Log Message

DFG should not always speculate that a ByVal access has an integer index
https://bugs.webkit.org/show_bug.cgi?id=69716

Reviewed by Oliver Hunt.
        
1% win on SunSpider, neutral elsewhere.

* dfg/DFGJITCodeGenerator.h:
(JSC::DFG::callOperation):
* dfg/DFGNode.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPropagator.cpp:
(JSC::DFG::Propagator::byValHasIntBase):
(JSC::DFG::Propagator::clobbersWorld):
(JSC::DFG::Propagator::getMethodLoadElimination):
(JSC::DFG::Propagator::checkStructureLoadElimination):
(JSC::DFG::Propagator::getByOffsetLoadElimination):
(JSC::DFG::Propagator::getPropertyStorageLoadElimination):
(JSC::DFG::Propagator::performNodeCSE):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (97029 => 97030)


--- trunk/Source/_javascript_Core/ChangeLog	2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-10-09 20:07:36 UTC (rev 97030)
@@ -1,3 +1,30 @@
+2011-10-09  Filip Pizlo  <fpi...@apple.com>
+
+        DFG should not always speculate that a ByVal access has an integer index
+        https://bugs.webkit.org/show_bug.cgi?id=69716
+
+        Reviewed by Oliver Hunt.
+        
+        1% win on SunSpider, neutral elsewhere.
+
+        * dfg/DFGJITCodeGenerator.h:
+        (JSC::DFG::callOperation):
+        * dfg/DFGNode.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPropagator.cpp:
+        (JSC::DFG::Propagator::byValHasIntBase):
+        (JSC::DFG::Propagator::clobbersWorld):
+        (JSC::DFG::Propagator::getMethodLoadElimination):
+        (JSC::DFG::Propagator::checkStructureLoadElimination):
+        (JSC::DFG::Propagator::getByOffsetLoadElimination):
+        (JSC::DFG::Propagator::getPropertyStorageLoadElimination):
+        (JSC::DFG::Propagator::performNodeCSE):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+
 2011-10-09  Yuqiang Xian  <yuqiang.x...@intel.com>
 
         Fix value profiling in 32_64 JIT

Modified: trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h (97029 => 97030)


--- trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h	2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.h	2011-10-09 20:07:36 UTC (rev 97030)
@@ -1154,6 +1154,14 @@
         appendCallWithExceptionCheck(operation);
         m_jit.move(GPRInfo::returnValueGPR, result);
     }
+    void callOperation(J_DFGOperation_ECJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
+    {
+        setupStubArguments(arg1, arg2);
+        m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+        appendCallWithExceptionCheck(operation);
+        m_jit.move(GPRInfo::returnValueGPR, result);
+    }
     void callOperation(V_DFGOperation_EJJP operation, GPRReg arg1, GPRReg arg2, void* pointer)
     {
         setupStubArguments(arg1, arg2);
@@ -1173,6 +1181,13 @@
 
         appendCallWithExceptionCheck(operation);
     }
+    void callOperation(V_DFGOperation_ECJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+    {
+        setupStubArguments(arg1, arg2, arg3);
+        m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+
+        appendCallWithExceptionCheck(operation);
+    }
     void callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
     {
         setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
@@ -1328,6 +1343,16 @@
         appendCallWithExceptionCheck(operation);
         setupResults(resultTag, resultPayload);
     }
+    void callOperation(J_DFGOperation_ECJ operation, GPRReg resultTag, GPRReg resultPayload, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload)
+    {
+        m_jit.push(arg2Tag);
+        m_jit.push(arg2Payload);
+        m_jit.push(arg1);
+        m_jit.push(GPRInfo::callFrameRegister);
+
+        appendCallWithExceptionCheck(operation);
+        setupResults(resultTag, resultPayload);
+    }
     void callOperation(V_DFGOperation_EJJP operation, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, void* pointer)
     {
         m_jit.push(JITCompiler::TrustedImm32(reinterpret_cast<int>(pointer)));
@@ -1355,7 +1380,18 @@
 
         appendCallWithExceptionCheck(operation);
     }
+    void callOperation(V_DFGOperation_ECJJ operation, GPRReg arg1, GPRReg arg2Tag, GPRReg arg2Payload, GPRReg arg3Tag, GPRReg arg3Payload)
+    {
+        m_jit.push(arg3Tag);
+        m_jit.push(arg3Payload);
+        m_jit.push(arg2Tag);
+        m_jit.push(arg2Payload);
+        m_jit.push(arg1);
+        m_jit.push(GPRInfo::callFrameRegister);
 
+        appendCallWithExceptionCheck(operation);
+    }
+
     void callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
     {
         m_jit.subPtr(TrustedImm32(2 * sizeof(double)), JITCompiler::stackPointerRegister);

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (97029 => 97030)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2011-10-09 20:07:36 UTC (rev 97030)
@@ -321,7 +321,7 @@
     /* PutByValAlias indicates a 'put' aliases a prior write to the same property. */\
     /* Since a put to 'length' may invalidate optimizations here, */\
     /* this must be the directly subsequent property put. */\
-    macro(GetByVal, NodeResultJS | NodeMustGenerate) \
+    macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \
     macro(PutByVal, NodeMustGenerate | NodeClobbersWorld) \
     macro(PutByValAlias, NodeMustGenerate | NodeClobbersWorld) \
     macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (97029 => 97030)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2011-10-09 20:07:36 UTC (rev 97030)
@@ -263,6 +263,26 @@
     return JSValue::encode(baseValue.get(exec, ident));
 }
 
+EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty)
+{
+    JSValue property = JSValue::decode(encodedProperty);
+
+    if (property.isUInt32())
+        return getByVal(exec, base, property.asUInt32());
+    if (property.isDouble()) {
+        double propertyAsDouble = property.asDouble();
+        uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
+        if (propertyAsUInt32 == propertyAsDouble)
+            return getByVal(exec, base, propertyAsUInt32);
+    } else if (property.isString()) {
+        if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec)))
+            return JSValue::encode(result);
+    }
+
+    Identifier ident(exec, property.toString(exec));
+    return JSValue::encode(JSValue(base).get(exec, ident));
+}
+
 EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName)
 {
     JSValue baseValue = JSValue::decode(encodedBase);
@@ -366,6 +386,16 @@
     operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
 }
 
+void DFG_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
+{
+    operationPutByValInternal<true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
+}
+
+void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
+{
+    operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
+}
+
 void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
 {
     // We should only get here if index is outside the existing vector.

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (97029 => 97030)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2011-10-09 20:07:36 UTC (rev 97030)
@@ -54,6 +54,7 @@
 typedef JSCell* DFG_OPERATION (*C_DFGOperation_EC)(ExecState*, JSCell*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EA)(ExecState*, JSArray*);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJA)(ExecState*, EncodedJSValue, JSArray*);
+typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJ)(ExecState*, EncodedJSValue);
 typedef EncodedJSValue DFG_OPERATION (*J_DFGOperation_EJP)(ExecState*, EncodedJSValue, void*);
@@ -65,6 +66,7 @@
 typedef RegisterSizedBoolean DFG_OPERATION (*Z_DFGOperation_EJ)(ExecState*, EncodedJSValue);
 typedef RegisterSizedBoolean DFG_OPERATION (*Z_DFGOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
 typedef void DFG_OPERATION (*V_DFGOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
+typedef void DFG_OPERATION (*V_DFGOperation_ECJJ)(ExecState*, JSCell*, EncodedJSValue, EncodedJSValue);
 typedef void DFG_OPERATION (*V_DFGOperation_EJJP)(ExecState*, EncodedJSValue, EncodedJSValue, void*);
 typedef void DFG_OPERATION (*V_DFGOperation_EJJI)(ExecState*, EncodedJSValue, EncodedJSValue, Identifier*);
 typedef double (*D_DFGOperation_DD)(double, double); // Using default calling conventions!
@@ -82,6 +84,7 @@
 EncodedJSValue DFG_OPERATION operationArithDiv(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
 EncodedJSValue DFG_OPERATION operationArithMod(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
 EncodedJSValue DFG_OPERATION operationGetByVal(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty);
+EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState*, JSCell*, EncodedJSValue encodedProperty);
 EncodedJSValue DFG_OPERATION operationGetById(ExecState*, EncodedJSValue encodedBase, Identifier*);
 EncodedJSValue DFG_OPERATION operationGetByIdBuildList(ExecState*, EncodedJSValue encodedBase, Identifier*);
 EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildList(ExecState*, EncodedJSValue encodedBase, Identifier*);
@@ -100,6 +103,8 @@
 void DFG_OPERATION operationThrowHasInstanceError(ExecState*, EncodedJSValue base);
 void DFG_OPERATION operationPutByValStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
 void DFG_OPERATION operationPutByValNonStrict(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
+void DFG_OPERATION operationPutByValCellStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
+void DFG_OPERATION operationPutByValCellNonStrict(ExecState*, JSCell*, EncodedJSValue encodedProperty, EncodedJSValue encodedValue);
 void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState*, JSArray*, int32_t index, EncodedJSValue encodedValue);
 EncodedJSValue DFG_OPERATION operationArrayPush(ExecState*, EncodedJSValue encodedValue, JSArray*);
 EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray*);

Modified: trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp (97029 => 97030)


--- trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp	2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGPropagator.cpp	2011-10-09 20:07:36 UTC (rev 97030)
@@ -880,6 +880,12 @@
         return isBooleanPrediction(prediction) || !prediction;
     }
     
+    bool byValHasIntBase(Node& node)
+    {
+        PredictedType prediction = m_graph[node.child2()].prediction();
+        return (prediction & PredictInt32) || !prediction;
+    }
+    
     bool clobbersWorld(NodeIndex nodeIndex)
     {
         Node& node = m_graph[nodeIndex];
@@ -897,6 +903,8 @@
             return !isPredictedNumerical(node);
         case LogicalNot:
             return !logicalNotIsPure(node);
+        case GetByVal:
+            return !byValHasIntBase(node);
         default:
             ASSERT_NOT_REACHED();
             return true; // If by some oddity we hit this case in release build it's safer to have CSE assume the worst.
@@ -1011,10 +1019,13 @@
                 
             case PutByVal:
             case PutByValAlias:
-                // PutByVal currently always speculates that it's accessing an array with an
-                // integer index, which means that it's impossible for it to cause a structure
-                // change.
-                break;
+                if (byValHasIntBase(node)) {
+                    // If PutByVal speculates that it's accessing an array with an
+                    // integer index, then it's impossible for it to cause a structure
+                    // change.
+                    break;
+                }
+                return NoNode;
                 
             case ArrayPush:
             case ArrayPop:
@@ -1076,10 +1087,13 @@
                 
             case PutByVal:
             case PutByValAlias:
-                // PutByVal currently always speculates that it's accessing an array with an
-                // integer index, which means that it's impossible for it to cause a structure
-                // change.
-                break;
+                if (byValHasIntBase(node)) {
+                    // If PutByVal speculates that it's accessing an array with an
+                    // integer index, then it's impossible for it to cause a structure
+                    // change.
+                    break;
+                }
+                return false;
                 
             default:
                 if (clobbersWorld(index))
@@ -1116,10 +1130,13 @@
                 
             case PutByVal:
             case PutByValAlias:
-                // PutByVal currently always speculates that it's accessing an array with an
-                // integer index, which means that it's impossible for it to cause a structure
-                // change.
-                break;
+                if (byValHasIntBase(node)) {
+                    // If PutByVal speculates that it's accessing an array with an
+                    // integer index, then it's impossible for it to cause a structure
+                    // change.
+                    break;
+                }
+                return NoNode;
                 
             default:
                 if (clobbersWorld(index))
@@ -1149,10 +1166,13 @@
                 
             case PutByVal:
             case PutByValAlias:
-                // PutByVal currently always speculates that it's accessing an array with an
-                // integer index, which means that it's impossible for it to cause a structure
-                // change.
-                break;
+                if (byValHasIntBase(node)) {
+                    // If PutByVal speculates that it's accessing an array with an
+                    // integer index, then it's impossible for it to cause a structure
+                    // change.
+                    break;
+                }
+                return NoNode;
                 
             default:
                 if (clobbersWorld(index))
@@ -1321,11 +1341,12 @@
             break;
             
         case GetByVal:
-            setReplacement(getByValLoadElimination(node.child1(), node.child2()));
+            if (byValHasIntBase(node))
+                setReplacement(getByValLoadElimination(node.child1(), node.child2()));
             break;
             
         case PutByVal:
-            if (getByValLoadElimination(node.child1(), node.child2()) != NoNode)
+            if (byValHasIntBase(node) && getByValLoadElimination(node.child1(), node.child2()) != NoNode)
                 node.op = PutByValAlias;
             break;
             

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (97029 => 97030)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2011-10-09 20:07:36 UTC (rev 97030)
@@ -1272,6 +1272,23 @@
     }
 
     case GetByVal: {
+        PredictedType basePrediction = at(node.child2()).prediction();
+        if (!(basePrediction & PredictInt32) && basePrediction) {
+            SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
+            JSValueOperand property(this, node.child2());
+            GPRReg baseGPR = base.gpr();
+            GPRReg propertyTagGPR = property.tagGPR();
+            GPRReg propertyPayloadGPR = property.payloadGPR();
+            
+            flushRegisters();
+            GPRResult2 resultTag(this);
+            GPRResult resultPayload(this);
+            callOperation(operationGetByValCell, resultTag.gpr(), resultPayload.gpr(), baseGPR, propertyTagGPR, propertyPayloadGPR);
+            
+            jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex);
+            break;
+        }
+
         if (at(node.child1()).prediction() == PredictString) {
             compileGetByValOnString(node);
             if (!m_compileOkay)
@@ -1314,6 +1331,24 @@
     }
 
     case PutByVal: {
+        PredictedType basePrediction = at(node.child2()).prediction();
+        if (!(basePrediction & PredictInt32) && basePrediction) {
+            SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right.
+            JSValueOperand property(this, node.child2());
+            JSValueOperand value(this, node.child3());
+            GPRReg baseGPR = base.gpr();
+            GPRReg propertyTagGPR = property.tagGPR();
+            GPRReg propertyPayloadGPR = property.payloadGPR();
+            GPRReg valueTagGPR = value.tagGPR();
+            GPRReg valuePayloadGPR = value.payloadGPR();
+            
+            flushRegisters();
+            callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR);
+            
+            noResult(m_compileIndex);
+            break;
+        }
+
         SpeculateCellOperand base(this, node.child1());
         SpeculateStrictInt32Operand property(this, node.child2());
         JSValueOperand value(this, node.child3());

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (97029 => 97030)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2011-10-09 16:15:19 UTC (rev 97029)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2011-10-09 20:07:36 UTC (rev 97030)
@@ -1383,6 +1383,21 @@
     }
 
     case GetByVal: {
+        PredictedType basePrediction = at(node.child2()).prediction();
+        if (!(basePrediction & PredictInt32) && basePrediction) {
+            JSValueOperand base(this, node.child1());
+            JSValueOperand property(this, node.child2());
+            GPRReg baseGPR = base.gpr();
+            GPRReg propertyGPR = property.gpr();
+            
+            flushRegisters();
+            GPRResult result(this);
+            callOperation(operationGetByVal, result.gpr(), baseGPR, propertyGPR);
+            
+            jsValueResult(result.gpr(), m_compileIndex);
+            break;
+        }
+        
         if (at(node.child1()).prediction() == PredictString) {
             compileGetByValOnString(node);
             if (!m_compileOkay)
@@ -1424,6 +1439,22 @@
     }
 
     case PutByVal: {
+        PredictedType basePrediction = at(node.child2()).prediction();
+        if (!(basePrediction & PredictInt32) && basePrediction) {
+            JSValueOperand arg1(this, node.child1());
+            JSValueOperand arg2(this, node.child2());
+            JSValueOperand arg3(this, node.child3());
+            GPRReg arg1GPR = arg1.gpr();
+            GPRReg arg2GPR = arg2.gpr();
+            GPRReg arg3GPR = arg3.gpr();
+            flushRegisters();
+            
+            callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValStrict : operationPutByValNonStrict, arg1GPR, arg2GPR, arg3GPR);
+            
+            noResult(m_compileIndex);
+            break;
+        }
+
         SpeculateCellOperand base(this, node.child1());
         SpeculateStrictInt32Operand property(this, node.child2());
         JSValueOperand value(this, node.child3());
@@ -1488,6 +1519,9 @@
     }
 
     case PutByValAlias: {
+        PredictedType basePrediction = at(node.child2()).prediction();
+        ASSERT_UNUSED(basePrediction, (basePrediction & PredictInt32) || !basePrediction);
+            
         SpeculateCellOperand base(this, node.child1());
         SpeculateStrictInt32Operand property(this, node.child2());
         JSValueOperand value(this, node.child3());
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to