Title: [185239] trunk
Revision
185239
Author
fpi...@apple.com
Date
2015-06-04 21:59:28 -0700 (Thu, 04 Jun 2015)

Log Message

Simplify unboxing of double JSValues known to be not NaN and not Int32
https://bugs.webkit.org/show_bug.cgi?id=145618

Reviewed by Geoffrey Garen.
Source/_javascript_Core:

        
In many cases we know that we most likely loaded a non-NaN double value from the heap.
Prior to this patch, we would do two branches before unboxing the double. This patch
reduces this to one branch in the common case. Before:
        
    if (is int32)
        unbox int32 and convert to double
    else if (is number)
        unbox double
    else
        exit
        
After:

    tmp = unbox double
    if (tmp == tmp)
        done
    else if (is int32)
        unbox int32 and convert to double
    else
        exit
        
We only use the new style if we have profiling that tells us that we are unlikely to see
either Int32 or NaN - since we will now exit on NaN and int32 requires an extra branch.
        
This is a 8% speed-up on Octane/box2d. On one microbenchmark this is a 25% speed-up.
        
Rolling this back in after I made DFG::SpeculativeJIT call a new version of unboxDouble()
that doesn't assert that the JSValue is a double, since we are intentionally using it
before doing the "is a double" test. This wasn't a problem on 32-bit since unboxDouble()
does no such assertion on 32-bit.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::observeUseKindOnNode):
(JSC::DFG::FixupPhase::fixEdgeRepresentation):
(JSC::DFG::FixupPhase::injectTypeConversionsForEdge):
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldSpeculateDouble):
(JSC::DFG::Node::shouldSpeculateDoubleReal):
(JSC::DFG::Node::shouldSpeculateNumber):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileDoubleRep):
(JSC::DFG::SpeculativeJIT::speculateNumber):
(JSC::DFG::SpeculativeJIT::speculateRealNumber):
(JSC::DFG::SpeculativeJIT::speculateDoubleRepReal):
(JSC::DFG::SpeculativeJIT::speculate):
(JSC::DFG::SpeculativeJIT::speculateDoubleReal): Deleted.
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isNumerical):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileDoubleRep):
(JSC::FTL::LowerDFGToLLVM::boxDouble):
(JSC::FTL::LowerDFGToLLVM::jsValueToStrictInt52):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateNumber):
(JSC::FTL::LowerDFGToLLVM::speculateRealNumber):
(JSC::FTL::LowerDFGToLLVM::speculateDoubleRepReal):
(JSC::FTL::LowerDFGToLLVM::jsValueToDouble): Deleted.
(JSC::FTL::LowerDFGToLLVM::speculateDoubleReal): Deleted.
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::branchIfNotOther):
(JSC::AssemblyHelpers::branchIfInt32):
(JSC::AssemblyHelpers::branchIfNotInt32):
(JSC::AssemblyHelpers::branchIfNumber):

LayoutTests:


* js/regress/double-real-use-expected.txt: Added.
* js/regress/double-real-use.html: Added.
* js/regress/script-tests/double-real-use.js: Added.
(foo):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (185238 => 185239)


--- trunk/LayoutTests/ChangeLog	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/LayoutTests/ChangeLog	2015-06-05 04:59:28 UTC (rev 185239)
@@ -1,3 +1,15 @@
+2015-06-03  Filip Pizlo  <fpi...@apple.com>
+
+        Simplify unboxing of double JSValues known to be not NaN and not Int32
+        https://bugs.webkit.org/show_bug.cgi?id=145618
+
+        Reviewed by Geoffrey Garen.
+
+        * js/regress/double-real-use-expected.txt: Added.
+        * js/regress/double-real-use.html: Added.
+        * js/regress/script-tests/double-real-use.js: Added.
+        (foo):
+
 2015-06-04  Joseph Pecoraro  <pecor...@apple.com>
 
         Web Inspector: Class constructor appearing as Object Tree property does not include parameters

Added: trunk/LayoutTests/js/regress/double-real-use-expected.txt (0 => 185239)


--- trunk/LayoutTests/js/regress/double-real-use-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/double-real-use-expected.txt	2015-06-05 04:59:28 UTC (rev 185239)
@@ -0,0 +1,10 @@
+JSRegress/double-real-use
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/double-real-use.html (0 => 185239)


--- trunk/LayoutTests/js/regress/double-real-use.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/double-real-use.html	2015-06-05 04:59:28 UTC (rev 185239)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/script-tests/double-real-use.js (0 => 185239)


--- trunk/LayoutTests/js/regress/script-tests/double-real-use.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/double-real-use.js	2015-06-05 04:59:28 UTC (rev 185239)
@@ -0,0 +1,16 @@
+function foo(a) {
+    var result = 0.0;
+    for (var i = 0; i < 1000; ++i) {
+        var o = a[i];
+        result += o.x + o.y;
+    }
+    return result;
+}
+
+noInline(foo);
+
+var array = [];
+for (var i = 0; i < 1000; ++i)
+    array.push({x:1.5, y:2.5});
+for (var i = 0; i < 10000; ++i)
+    foo(array);

Modified: trunk/Source/_javascript_Core/ChangeLog (185238 => 185239)


--- trunk/Source/_javascript_Core/ChangeLog	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-06-05 04:59:28 UTC (rev 185239)
@@ -1,3 +1,84 @@
+2015-06-03  Filip Pizlo  <fpi...@apple.com>
+
+        Simplify unboxing of double JSValues known to be not NaN and not Int32
+        https://bugs.webkit.org/show_bug.cgi?id=145618
+
+        Reviewed by Geoffrey Garen.
+        
+        In many cases we know that we most likely loaded a non-NaN double value from the heap.
+        Prior to this patch, we would do two branches before unboxing the double. This patch
+        reduces this to one branch in the common case. Before:
+        
+            if (is int32)
+                unbox int32 and convert to double
+            else if (is number)
+                unbox double
+            else
+                exit
+        
+        After:
+
+            tmp = unbox double
+            if (tmp == tmp)
+                done
+            else if (is int32)
+                unbox int32 and convert to double
+            else
+                exit
+        
+        We only use the new style if we have profiling that tells us that we are unlikely to see
+        either Int32 or NaN - since we will now exit on NaN and int32 requires an extra branch.
+        
+        This is a 8% speed-up on Octane/box2d. On one microbenchmark this is a 25% speed-up.
+        
+        Rolling this back in after I made DFG::SpeculativeJIT call a new version of unboxDouble()
+        that doesn't assert that the JSValue is a double, since we are intentionally using it
+        before doing the "is a double" test. This wasn't a problem on 32-bit since unboxDouble()
+        does no such assertion on 32-bit.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::observeUseKindOnNode):
+        (JSC::DFG::FixupPhase::fixEdgeRepresentation):
+        (JSC::DFG::FixupPhase::injectTypeConversionsForEdge):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::shouldSpeculateDouble):
+        (JSC::DFG::Node::shouldSpeculateDoubleReal):
+        (JSC::DFG::Node::shouldSpeculateNumber):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::SafeToExecuteEdge::operator()):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileDoubleRep):
+        (JSC::DFG::SpeculativeJIT::speculateNumber):
+        (JSC::DFG::SpeculativeJIT::speculateRealNumber):
+        (JSC::DFG::SpeculativeJIT::speculateDoubleRepReal):
+        (JSC::DFG::SpeculativeJIT::speculate):
+        (JSC::DFG::SpeculativeJIT::speculateDoubleReal): Deleted.
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGUseKind.cpp:
+        (WTF::printInternal):
+        * dfg/DFGUseKind.h:
+        (JSC::DFG::typeFilterFor):
+        (JSC::DFG::isNumerical):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileDoubleRep):
+        (JSC::FTL::LowerDFGToLLVM::boxDouble):
+        (JSC::FTL::LowerDFGToLLVM::jsValueToStrictInt52):
+        (JSC::FTL::LowerDFGToLLVM::speculate):
+        (JSC::FTL::LowerDFGToLLVM::speculateNumber):
+        (JSC::FTL::LowerDFGToLLVM::speculateRealNumber):
+        (JSC::FTL::LowerDFGToLLVM::speculateDoubleRepReal):
+        (JSC::FTL::LowerDFGToLLVM::jsValueToDouble): Deleted.
+        (JSC::FTL::LowerDFGToLLVM::speculateDoubleReal): Deleted.
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::branchIfNotOther):
+        (JSC::AssemblyHelpers::branchIfInt32):
+        (JSC::AssemblyHelpers::branchIfNotInt32):
+        (JSC::AssemblyHelpers::branchIfNumber):
+
 2015-06-04  Joseph Pecoraro  <pecor...@apple.com>
 
         Web Inspector: Class constructor appearing as Object Tree property does not include parameters

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (185238 => 185239)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-06-05 04:59:28 UTC (rev 185239)
@@ -378,6 +378,7 @@
 
         case Int52RepUse:
         case NumberUse:
+        case RealNumberUse:
             break;
 
         default:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (185238 => 185239)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-06-05 04:59:28 UTC (rev 185239)
@@ -1723,6 +1723,7 @@
                 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
             break;
         case NumberUse:
+        case RealNumberUse:
         case DoubleRepUse:
         case DoubleRepRealUse:
             if (variable->doubleFormatState() == UsingDoubleFormat)
@@ -2102,6 +2103,13 @@
                 edge.setUseKind(Int52RepUse);
             break;
             
+        case RealNumberUse:
+            if (edge->hasDoubleResult())
+                edge.setUseKind(DoubleRepRealUse);
+            else if (edge->hasInt52Result())
+                edge.setUseKind(Int52RepUse);
+            break;
+            
         default:
             break;
         }
@@ -2128,9 +2136,13 @@
                     m_indexInBlock, SpecInt52AsDouble, DoubleRep, node->origin,
                     Edge(edge.node(), Int52RepUse));
             } else {
-                UseKind useKind = NotCellUse;
-                if (edge->shouldSpeculateNumber())
+                UseKind useKind;
+                if (edge->shouldSpeculateDoubleReal())
+                    useKind = RealNumberUse;
+                else if (edge->shouldSpeculateNumber())
                     useKind = NumberUse;
+                else
+                    useKind = NotCellUse;
 
                 result = m_insertionSet.insertNode(
                     m_indexInBlock, SpecBytecodeDouble, DoubleRep, node->origin,

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (185238 => 185239)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-06-05 04:59:28 UTC (rev 185239)
@@ -1762,6 +1762,11 @@
         return isDoubleSpeculation(prediction());
     }
     
+    bool shouldSpeculateDoubleReal()
+    {
+        return isDoubleRealSpeculation(prediction());
+    }
+    
     bool shouldSpeculateNumber()
     {
         return isFullNumberSpeculation(prediction());

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (185238 => 185239)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2015-06-05 04:59:28 UTC (rev 185239)
@@ -50,6 +50,7 @@
         case DoubleRepRealUse:
         case Int52RepUse:
         case NumberUse:
+        case RealNumberUse:
         case BooleanUse:
         case CellUse:
         case ObjectUse:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (185238 => 185239)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-06-05 04:59:28 UTC (rev 185239)
@@ -2066,6 +2066,37 @@
 void SpeculativeJIT::compileDoubleRep(Node* node)
 {
     switch (node->child1().useKind()) {
+    case RealNumberUse: {
+        JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
+        FPRTemporary result(this);
+        
+        JSValueRegs op1Regs = op1.jsValueRegs();
+        FPRReg resultFPR = result.fpr();
+        
+#if USE(JSVALUE64)
+        GPRTemporary temp(this);
+        GPRReg tempGPR = temp.gpr();
+        m_jit.move(op1Regs.gpr(), tempGPR);
+        m_jit.unboxDoubleWithoutAssertions(tempGPR, resultFPR);
+#else
+        FPRTemporary temp(this);
+        FPRReg tempFPR = temp.fpr();
+        unboxDouble(op1Regs.tagGPR(), op1Regs.payloadGPR(), resultFPR, tempFPR);
+#endif
+        
+        JITCompiler::Jump done = m_jit.branchDouble(
+            JITCompiler::DoubleEqual, resultFPR, resultFPR);
+        
+        DFG_TYPE_CHECK(
+            op1Regs, node->child1(), SpecBytecodeRealNumber, m_jit.branchIfNotInt32(op1Regs));
+        m_jit.convertInt32ToDouble(op1Regs.payloadGPR(), resultFPR);
+        
+        done.link(&m_jit);
+        
+        doubleResult(resultFPR, node);
+        return;
+    }
+    
     case NotCellUse:
     case NumberUse: {
         ASSERT(!node->child1()->isNumberConstant()); // This should have been constant folded.
@@ -5372,11 +5403,41 @@
 #endif
 }
 
-void SpeculativeJIT::speculateDoubleReal(Edge edge)
+void SpeculativeJIT::speculateRealNumber(Edge edge)
 {
     if (!needsTypeCheck(edge, SpecDoubleReal))
         return;
     
+    JSValueOperand op1(this, edge, ManualOperandSpeculation);
+    FPRTemporary result(this);
+    
+    JSValueRegs op1Regs = op1.jsValueRegs();
+    FPRReg resultFPR = result.fpr();
+    
+#if USE(JSVALUE64)
+    GPRTemporary temp(this);
+    GPRReg tempGPR = temp.gpr();
+    m_jit.move(op1Regs.gpr(), tempGPR);
+    m_jit.unboxDoubleWithoutAssertions(tempGPR, resultFPR);
+#else
+    FPRTemporary temp(this);
+    FPRReg tempFPR = temp.fpr();
+    unboxDouble(op1Regs.tagGPR(), op1Regs.payloadGPR(), resultFPR, tempFPR);
+#endif
+    
+    JITCompiler::Jump done = m_jit.branchDouble(
+        JITCompiler::DoubleEqual, resultFPR, resultFPR);
+
+    typeCheck(op1Regs, edge, SpecBytecodeRealNumber, m_jit.branchIfNotInt32(op1Regs));
+    
+    done.link(&m_jit);
+}
+
+void SpeculativeJIT::speculateDoubleRepReal(Edge edge)
+{
+    if (!needsTypeCheck(edge, SpecDoubleReal))
+        return;
+    
     SpeculateDoubleOperand operand(this, edge);
     FPRReg fpr = operand.fpr();
     typeCheck(
@@ -5641,8 +5702,11 @@
     case NumberUse:
         speculateNumber(edge);
         break;
+    case RealNumberUse:
+        speculateRealNumber(edge);
+        break;
     case DoubleRepRealUse:
-        speculateDoubleReal(edge);
+        speculateDoubleRepReal(edge);
         break;
 #if USE(JSVALUE64)
     case MachineIntUse:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (185238 => 185239)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-06-05 04:59:28 UTC (rev 185239)
@@ -2372,7 +2372,8 @@
     void speculateDoubleRepMachineInt(Edge);
 #endif // USE(JSVALUE64)
     void speculateNumber(Edge);
-    void speculateDoubleReal(Edge);
+    void speculateRealNumber(Edge);
+    void speculateDoubleRepReal(Edge);
     void speculateBoolean(Edge);
     void speculateCell(Edge);
     void speculateObject(Edge);

Modified: trunk/Source/_javascript_Core/dfg/DFGUseKind.cpp (185238 => 185239)


--- trunk/Source/_javascript_Core/dfg/DFGUseKind.cpp	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/dfg/DFGUseKind.cpp	2015-06-05 04:59:28 UTC (rev 185239)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -55,6 +55,9 @@
     case NumberUse:
         out.print("Number");
         return;
+    case RealNumberUse:
+        out.print("RealNumber");
+        return;
     case DoubleRepUse:
         out.print("DoubleRep");
         return;

Modified: trunk/Source/_javascript_Core/dfg/DFGUseKind.h (185238 => 185239)


--- trunk/Source/_javascript_Core/dfg/DFGUseKind.h	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/dfg/DFGUseKind.h	2015-06-05 04:59:28 UTC (rev 185239)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -46,6 +46,7 @@
     KnownInt32Use,
     MachineIntUse,
     NumberUse,
+    RealNumberUse,
     BooleanUse,
     CellUse,
     KnownCellUse,
@@ -90,6 +91,8 @@
         return SpecInt32 | SpecInt52AsDouble;
     case NumberUse:
         return SpecBytecodeNumber;
+    case RealNumberUse:
+        return SpecBytecodeRealNumber;
     case DoubleRepUse:
         return SpecFullDouble;
     case DoubleRepRealUse:
@@ -158,6 +161,7 @@
     case Int32Use:
     case KnownInt32Use:
     case NumberUse:
+    case RealNumberUse:
     case Int52RepUse:
     case DoubleRepUse:
     case DoubleRepRealUse:

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (185238 => 185239)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2015-06-05 04:59:28 UTC (rev 185239)
@@ -400,6 +400,7 @@
                 case KnownInt32Use:
                 case Int52RepUse:
                 case NumberUse:
+                case RealNumberUse:
                 case DoubleRepUse:
                 case DoubleRepRealUse:
                 case BooleanUse:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (185238 => 185239)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-06-05 04:59:28 UTC (rev 185239)
@@ -958,12 +958,113 @@
     void compileDoubleRep()
     {
         switch (m_node->child1().useKind()) {
+        case RealNumberUse: {
+            LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
+            
+            LValue doubleValue = unboxDouble(value);
+            
+            LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("DoubleRep RealNumberUse int case"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("DoubleRep continuation"));
+            
+            ValueFromBlock fastResult = m_out.anchor(doubleValue);
+            m_out.branch(
+                m_out.doubleEqual(doubleValue, doubleValue),
+                usually(continuation), rarely(intCase));
+            
+            LBasicBlock lastNext = m_out.appendTo(intCase, continuation);
+            
+            FTL_TYPE_CHECK(
+                jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber,
+                isNotInt32(value, provenType(m_node->child1()) & ~SpecFullDouble));
+            ValueFromBlock slowResult = m_out.anchor(m_out.intToDouble(unboxInt32(value)));
+            m_out.jump(continuation);
+            
+            m_out.appendTo(continuation, lastNext);
+            
+            setDouble(m_out.phi(m_out.doubleType, fastResult, slowResult));
+            return;
+        }
+            
         case NotCellUse:
         case NumberUse: {
             bool shouldConvertNonNumber = m_node->child1().useKind() == NotCellUse;
+            
+            LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
 
-            LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
-            setDouble(jsValueToDouble(m_node->child1(), value, shouldConvertNonNumber));
+            LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing int case"));
+            LBasicBlock doubleTesting = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing double case"));
+            LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing double case"));
+            LBasicBlock nonDoubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing undefined case"));
+            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing continuation"));
+            
+            m_out.branch(
+                isNotInt32(value, provenType(m_node->child1())),
+                unsure(doubleTesting), unsure(intCase));
+            
+            LBasicBlock lastNext = m_out.appendTo(intCase, doubleTesting);
+            
+            ValueFromBlock intToDouble = m_out.anchor(
+                m_out.intToDouble(unboxInt32(value)));
+            m_out.jump(continuation);
+            
+            m_out.appendTo(doubleTesting, doubleCase);
+            LValue valueIsNumber = isNumber(value, provenType(m_node->child1()));
+            m_out.branch(valueIsNumber, usually(doubleCase), rarely(nonDoubleCase));
+
+            m_out.appendTo(doubleCase, nonDoubleCase);
+            ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(value));
+            m_out.jump(continuation);
+
+            if (shouldConvertNonNumber) {
+                LBasicBlock undefinedCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting undefined case"));
+                LBasicBlock testNullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing null case"));
+                LBasicBlock nullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting null case"));
+                LBasicBlock testBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing boolean true case"));
+                LBasicBlock convertBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean true case"));
+                LBasicBlock convertBooleanFalseCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean false case"));
+
+                m_out.appendTo(nonDoubleCase, undefinedCase);
+                LValue valueIsUndefined = m_out.equal(value, m_out.constInt64(ValueUndefined));
+                m_out.branch(valueIsUndefined, unsure(undefinedCase), unsure(testNullCase));
+
+                m_out.appendTo(undefinedCase, testNullCase);
+                ValueFromBlock convertedUndefined = m_out.anchor(m_out.constDouble(PNaN));
+                m_out.jump(continuation);
+
+                m_out.appendTo(testNullCase, nullCase);
+                LValue valueIsNull = m_out.equal(value, m_out.constInt64(ValueNull));
+                m_out.branch(valueIsNull, unsure(nullCase), unsure(testBooleanTrueCase));
+
+                m_out.appendTo(nullCase, testBooleanTrueCase);
+                ValueFromBlock convertedNull = m_out.anchor(m_out.constDouble(0));
+                m_out.jump(continuation);
+
+                m_out.appendTo(testBooleanTrueCase, convertBooleanTrueCase);
+                LValue valueIsBooleanTrue = m_out.equal(value, m_out.constInt64(ValueTrue));
+                m_out.branch(valueIsBooleanTrue, unsure(convertBooleanTrueCase), unsure(convertBooleanFalseCase));
+
+                m_out.appendTo(convertBooleanTrueCase, convertBooleanFalseCase);
+                ValueFromBlock convertedTrue = m_out.anchor(m_out.constDouble(1));
+                m_out.jump(continuation);
+
+                m_out.appendTo(convertBooleanFalseCase, continuation);
+
+                LValue valueIsNotBooleanFalse = m_out.notEqual(value, m_out.constInt64(ValueFalse));
+                FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), ~SpecCell, valueIsNotBooleanFalse);
+                ValueFromBlock convertedFalse = m_out.anchor(m_out.constDouble(0));
+                m_out.jump(continuation);
+
+                m_out.appendTo(continuation, lastNext);
+                setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble, convertedUndefined, convertedNull, convertedTrue, convertedFalse));
+                return;
+            }
+            m_out.appendTo(nonDoubleCase, continuation);
+            FTL_TYPE_CHECK(jsValueValue(value), m_node->child1(), SpecBytecodeNumber, m_out.booleanTrue);
+            m_out.unreachable();
+
+            m_out.appendTo(continuation, lastNext);
+
+            setDouble(m_out.phi(m_out.doubleType, intToDouble, unboxedDouble));
             return;
         }
             
@@ -7293,87 +7394,6 @@
     {
         return m_out.sub(m_out.bitCast(doubleValue, m_out.int64), m_tagTypeNumber);
     }
-    LValue jsValueToDouble(Edge edge, LValue boxedValue, bool shouldConvertNonNumber)
-    {
-        LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing int case"));
-        LBasicBlock doubleTesting = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing double case"));
-        LBasicBlock doubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing double case"));
-        LBasicBlock nonDoubleCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing undefined case"));
-        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("jsValueToDouble unboxing continuation"));
-            
-        LValue isNotInt32;
-        if (!m_interpreter.needsTypeCheck(edge, SpecInt32))
-            isNotInt32 = m_out.booleanFalse;
-        else if (!m_interpreter.needsTypeCheck(edge, ~SpecInt32))
-            isNotInt32 = m_out.booleanTrue;
-        else
-            isNotInt32 = this->isNotInt32(boxedValue);
-        m_out.branch(isNotInt32, unsure(doubleTesting), unsure(intCase));
-            
-        LBasicBlock lastNext = m_out.appendTo(intCase, doubleTesting);
-            
-        ValueFromBlock intToDouble = m_out.anchor(
-            m_out.intToDouble(unboxInt32(boxedValue)));
-        m_out.jump(continuation);
-            
-        m_out.appendTo(doubleTesting, doubleCase);
-        LValue valueIsNumber = isNumber(boxedValue);
-        m_out.branch(valueIsNumber, usually(doubleCase), rarely(nonDoubleCase));
-
-        m_out.appendTo(doubleCase, nonDoubleCase);
-        ValueFromBlock unboxedDouble = m_out.anchor(unboxDouble(boxedValue));
-        m_out.jump(continuation);
-
-        if (shouldConvertNonNumber) {
-            LBasicBlock undefinedCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting undefined case"));
-            LBasicBlock testNullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing null case"));
-            LBasicBlock nullCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble converting null case"));
-            LBasicBlock testBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble testing boolean true case"));
-            LBasicBlock convertBooleanTrueCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean true case"));
-            LBasicBlock convertBooleanFalseCase = FTL_NEW_BLOCK(m_out, ("jsValueToDouble convert boolean false case"));
-
-            m_out.appendTo(nonDoubleCase, undefinedCase);
-            LValue valueIsUndefined = m_out.equal(boxedValue, m_out.constInt64(ValueUndefined));
-            m_out.branch(valueIsUndefined, unsure(undefinedCase), unsure(testNullCase));
-
-            m_out.appendTo(undefinedCase, testNullCase);
-            ValueFromBlock convertedUndefined = m_out.anchor(m_out.constDouble(PNaN));
-            m_out.jump(continuation);
-
-            m_out.appendTo(testNullCase, nullCase);
-            LValue valueIsNull = m_out.equal(boxedValue, m_out.constInt64(ValueNull));
-            m_out.branch(valueIsNull, unsure(nullCase), unsure(testBooleanTrueCase));
-
-            m_out.appendTo(nullCase, testBooleanTrueCase);
-            ValueFromBlock convertedNull = m_out.anchor(m_out.constDouble(0));
-            m_out.jump(continuation);
-
-            m_out.appendTo(testBooleanTrueCase, convertBooleanTrueCase);
-            LValue valueIsBooleanTrue = m_out.equal(boxedValue, m_out.constInt64(ValueTrue));
-            m_out.branch(valueIsBooleanTrue, unsure(convertBooleanTrueCase), unsure(convertBooleanFalseCase));
-
-            m_out.appendTo(convertBooleanTrueCase, convertBooleanFalseCase);
-            ValueFromBlock convertedTrue = m_out.anchor(m_out.constDouble(1));
-            m_out.jump(continuation);
-
-            m_out.appendTo(convertBooleanFalseCase, continuation);
-
-            LValue valueIsNotBooleanFalse = m_out.notEqual(boxedValue, m_out.constInt64(ValueFalse));
-            FTL_TYPE_CHECK(jsValueValue(boxedValue), edge, ~SpecCell, valueIsNotBooleanFalse);
-            ValueFromBlock convertedFalse = m_out.anchor(m_out.constDouble(0));
-            m_out.jump(continuation);
-
-            m_out.appendTo(continuation, lastNext);
-            return m_out.phi(m_out.doubleType, intToDouble, unboxedDouble, convertedUndefined, convertedNull, convertedTrue, convertedFalse);
-        }
-        m_out.appendTo(nonDoubleCase, continuation);
-        FTL_TYPE_CHECK(jsValueValue(boxedValue), edge, SpecBytecodeNumber, m_out.booleanTrue);
-        m_out.unreachable();
-
-        m_out.appendTo(continuation, lastNext);
-
-        return m_out.phi(m_out.doubleType, intToDouble, unboxedDouble);
-    }
     
     LValue jsValueToStrictInt52(Edge edge, LValue boxedValue)
     {
@@ -7590,8 +7610,11 @@
         case NumberUse:
             speculateNumber(edge);
             break;
+        case RealNumberUse:
+            speculateRealNumber(edge);
+            break;
         case DoubleRepRealUse:
-            speculateDoubleReal(edge);
+            speculateDoubleRepReal(edge);
             break;
         case DoubleRepMachineIntUse:
             speculateDoubleRepMachineInt(edge);
@@ -7917,12 +7940,38 @@
         FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBytecodeNumber, isNotNumber(value));
     }
     
-    void speculateDoubleReal(Edge edge)
+    void speculateRealNumber(Edge edge)
     {
         // Do an early return here because lowDouble() can create a lot of control flow.
         if (!m_interpreter.needsTypeCheck(edge))
             return;
         
+        LValue value = lowJSValue(edge, ManualOperandSpeculation);
+        LValue doubleValue = unboxDouble(value);
+        
+        LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("speculateRealNumber int case"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("speculateRealNumber continuation"));
+        
+        m_out.branch(
+            m_out.doubleEqual(doubleValue, doubleValue),
+            usually(continuation), rarely(intCase));
+        
+        LBasicBlock lastNext = m_out.appendTo(intCase, continuation);
+        
+        typeCheck(
+            jsValueValue(value), m_node->child1(), SpecBytecodeRealNumber,
+            isNotInt32(value, provenType(m_node->child1()) & ~SpecFullDouble));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+    }
+    
+    void speculateDoubleRepReal(Edge edge)
+    {
+        // Do an early return here because lowDouble() can create a lot of control flow.
+        if (!m_interpreter.needsTypeCheck(edge))
+            return;
+        
         LValue value = lowDouble(edge);
         FTL_TYPE_CHECK(
             doubleValue(value), edge, SpecDoubleReal,

Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (185238 => 185239)


--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2015-06-05 04:46:17 UTC (rev 185238)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h	2015-06-05 04:59:28 UTC (rev 185239)
@@ -457,6 +457,24 @@
 #endif
     }
     
+    Jump branchIfInt32(JSValueRegs regs)
+    {
+#if USE(JSVALUE64)
+        return branch64(AboveOrEqual, regs.gpr(), GPRInfo::tagTypeNumberRegister);
+#else
+        return branch32(Equal, regs.tagGPR(), TrustedImm32(JSValue::Int32Tag));
+#endif
+    }
+    
+    Jump branchIfNotInt32(JSValueRegs regs)
+    {
+#if USE(JSVALUE64)
+        return branch64(Below, regs.gpr(), GPRInfo::tagTypeNumberRegister);
+#else
+        return branch32(NotEqual, regs.tagGPR(), TrustedImm32(JSValue::Int32Tag));
+#endif
+    }
+
     // Note that the tempGPR is not used in 64-bit mode.
     Jump branchIfNumber(JSValueRegs regs, GPRReg tempGPR)
     {
@@ -736,13 +754,17 @@
         jitAssertIsJSDouble(gpr);
         return gpr;
     }
-    FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
+    FPRReg unboxDoubleWithoutAssertions(GPRReg gpr, FPRReg fpr)
     {
-        jitAssertIsJSDouble(gpr);
         add64(GPRInfo::tagTypeNumberRegister, gpr);
         move64ToDouble(gpr, fpr);
         return fpr;
     }
+    FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
+    {
+        jitAssertIsJSDouble(gpr);
+        return unboxDoubleWithoutAssertions(gpr, fpr);
+    }
     
     void boxDouble(FPRReg fpr, JSValueRegs regs)
     {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to