Title: [184933] trunk
Revision
184933
Author
[email protected]
Date
2015-05-27 18:30:58 -0700 (Wed, 27 May 2015)

Log Message

[JSC] Add undefined->double conversion to DoubleRep
https://bugs.webkit.org/show_bug.cgi?id=145293

Patch by Benjamin Poulain <[email protected]> on 2015-05-27
Reviewed by Filip Pizlo.

Source/_javascript_Core:

This patch adds undefined to double conversion to the DoubleRep
node for the cases were we speculate "undefined" as part of the types
processed.

The use case is doing math with accidental out-of-bounds access. For example,
something like:
    for (var i = 0; i <= length; ++i)
        ouptput += array[i];

would cause us to OSR exit every time i === length.

When hitting one of those cases, we would already speculate double math,
but the DoubleRep node was unable to convert the undefined and would exit.

With this patch the use kind NotCellUse cover this conversion for DoubleRep.
I have been quite conservative so in general we will not find "undefined"
until a few recompile but being optimistic seems better since this is a corner case.

This patch is a 80% progression on WebXPRT's DNA Sequencing test.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::injectTypeConversionsForEdge):
* dfg/DFGNode.h:
(JSC::DFG::Node::sawUndefined):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileDoubleRep):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileDoubleRep):
(JSC::FTL::LowerDFGToLLVM::jsValueToDouble):
* tests/stress/double-rep-with-undefined.js: Added.
(addArgsNumberAndUndefined):
(addArgsInt32AndUndefined):
(testFallbackWithDouble):
(addArgsDoubleAndUndefined):
(testFallbackWithObject.):
(testFallbackWithObject):
(addArgsOnlyUndefined):
(testFallbackWithString):

LayoutTests:

* js/regress/math-with-out-of-bounds-array-values-expected.txt: Added.
* js/regress/math-with-out-of-bounds-array-values.html: Added.
* js/regress/script-tests/math-with-out-of-bounds-array-values.js: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (184932 => 184933)


--- trunk/LayoutTests/ChangeLog	2015-05-28 00:39:35 UTC (rev 184932)
+++ trunk/LayoutTests/ChangeLog	2015-05-28 01:30:58 UTC (rev 184933)
@@ -1,3 +1,14 @@
+2015-05-27  Benjamin Poulain  <[email protected]>
+
+        [JSC] Add undefined->double conversion to DoubleRep
+        https://bugs.webkit.org/show_bug.cgi?id=145293
+
+        Reviewed by Filip Pizlo.
+
+        * js/regress/math-with-out-of-bounds-array-values-expected.txt: Added.
+        * js/regress/math-with-out-of-bounds-array-values.html: Added.
+        * js/regress/script-tests/math-with-out-of-bounds-array-values.js: Added.
+
 2015-05-27  Simon Fraser  <[email protected]>
 
         REGRESSION (r183820): webkit.org/blog/ background painting issue on reload, when the page contains videos

Added: trunk/LayoutTests/js/regress/math-with-out-of-bounds-array-values-expected.txt (0 => 184933)


--- trunk/LayoutTests/js/regress/math-with-out-of-bounds-array-values-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/math-with-out-of-bounds-array-values-expected.txt	2015-05-28 01:30:58 UTC (rev 184933)
@@ -0,0 +1,10 @@
+JSRegress/math-with-out-of-bounds-array-values
+
+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/math-with-out-of-bounds-array-values.html (0 => 184933)


--- trunk/LayoutTests/js/regress/math-with-out-of-bounds-array-values.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/math-with-out-of-bounds-array-values.html	2015-05-28 01:30:58 UTC (rev 184933)
@@ -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/math-with-out-of-bounds-array-values.js (0 => 184933)


--- trunk/LayoutTests/js/regress/script-tests/math-with-out-of-bounds-array-values.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/math-with-out-of-bounds-array-values.js	2015-05-28 01:30:58 UTC (rev 184933)
@@ -0,0 +1,19 @@
+function mathWithOutOfBoundsAccess(arrayA, arrayB)
+{
+    var output = 0;
+    for (var i = 0; i < 10; ++i) {
+        output += (arrayA[i] + arrayB[i]);
+    }
+    return output;
+}
+
+noInline(mathWithOutOfBoundsAccess);
+
+function test() {
+    var integerArray = [0, 1, 2, 3, 4];
+    var doubleArray = [0.1, 1.2, 2.3, 3.4, 4.5];
+
+    for (var i = 0; i < 1e5; ++i)
+        mathWithOutOfBoundsAccess(integerArray, doubleArray);
+}
+test();
\ No newline at end of file

Modified: trunk/Source/_javascript_Core/ChangeLog (184932 => 184933)


--- trunk/Source/_javascript_Core/ChangeLog	2015-05-28 00:39:35 UTC (rev 184932)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-05-28 01:30:58 UTC (rev 184933)
@@ -1,3 +1,61 @@
+2015-05-27  Benjamin Poulain  <[email protected]>
+
+        [JSC] Add undefined->double conversion to DoubleRep
+        https://bugs.webkit.org/show_bug.cgi?id=145293
+
+        Reviewed by Filip Pizlo.
+
+        This patch adds undefined to double conversion to the DoubleRep
+        node for the cases were we speculate "undefined" as part of the types
+        processed.
+
+        The use case is doing math with accidental out-of-bounds access. For example,
+        something like:
+            for (var i = 0; i <= length; ++i)
+                ouptput += array[i];
+
+        would cause us to OSR exit every time i === length.
+
+        When hitting one of those cases, we would already speculate double math,
+        but the DoubleRep node was unable to convert the undefined and would exit.
+
+        With this patch the use kind NotCellUse cover this conversion for DoubleRep.
+        I have been quite conservative so in general we will not find "undefined"
+        until a few recompile but being optimistic seems better since this is a corner case.
+
+        This patch is a 80% progression on WebXPRT's DNA Sequencing test.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::injectTypeConversionsForEdge):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::sawUndefined):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::SafeToExecuteEdge::operator()):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileDoubleRep):
+        * dfg/DFGUseKind.cpp:
+        (WTF::printInternal):
+        * dfg/DFGUseKind.h:
+        (JSC::DFG::typeFilterFor):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileDoubleRep):
+        (JSC::FTL::LowerDFGToLLVM::jsValueToDouble):
+        * tests/stress/double-rep-with-undefined.js: Added.
+        (addArgsNumberAndUndefined):
+        (addArgsInt32AndUndefined):
+        (testFallbackWithDouble):
+        (addArgsDoubleAndUndefined):
+        (testFallbackWithObject.):
+        (testFallbackWithObject):
+        (addArgsOnlyUndefined):
+        (testFallbackWithString):
+
 2015-05-27  Dean Jackson  <[email protected]>
 
         img.currentSrc problem in strict mode with old picturefill

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (184932 => 184933)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-05-28 00:39:35 UTC (rev 184932)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2015-05-28 01:30:58 UTC (rev 184933)
@@ -360,7 +360,30 @@
             setConstant(node, jsDoubleNumber(child.asNumber()));
             break;
         }
-        forNode(node).setType(m_graph, forNode(node->child1()).m_type);
+
+        SpeculatedType type = forNode(node->child1()).m_type;
+        switch (node->child1().useKind()) {
+        case NotCellUse: {
+            if (type & SpecOther) {
+                type &= ~SpecOther;
+                type |= SpecDoublePureNaN | SpecBoolInt32; // Null becomes zero, undefined becomes NaN.
+            }
+            if (type & SpecBoolean) {
+                type &= ~SpecBoolean;
+                type |= SpecBoolInt32; // True becomes 1, false becomes 0.
+            }
+            type &= SpecBytecodeNumber;
+            break;
+        }
+
+        case Int52RepUse:
+        case NumberUse:
+            break;
+
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        forNode(node).setType(type);
         forNode(node).fixTypeForRepresentation(m_graph, node);
         break;
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (184932 => 184933)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-05-28 00:39:35 UTC (rev 184932)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-05-28 01:30:58 UTC (rev 184933)
@@ -2128,9 +2128,13 @@
                     m_indexInBlock, SpecInt52AsDouble, DoubleRep, node->origin,
                     Edge(edge.node(), Int52RepUse));
             } else {
+                UseKind useKind = NotCellUse;
+                if (edge->shouldSpeculateNumber())
+                    useKind = NumberUse;
+
                 result = m_insertionSet.insertNode(
                     m_indexInBlock, SpecBytecodeDouble, DoubleRep, node->origin,
-                    Edge(edge.node(), NumberUse));
+                    Edge(edge.node(), useKind));
             }
 
             edge.setNode(result);

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (184932 => 184933)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-05-28 00:39:35 UTC (rev 184932)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2015-05-28 01:30:58 UTC (rev 184933)
@@ -402,6 +402,12 @@
                 SpecNone);
             
             switch (arrayMode.type()) {
+            case Array::Int32:
+                if (arrayMode.isOutOfBounds())
+                    changed |= mergePrediction(node->getHeapPrediction() | SpecInt32);
+                else
+                    changed |= mergePrediction(SpecInt32);
+                break;
             case Array::Double:
                 if (arrayMode.isOutOfBounds())
                     changed |= mergePrediction(node->getHeapPrediction() | SpecDoubleReal);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (184932 => 184933)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-05-28 00:39:35 UTC (rev 184932)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2015-05-28 01:30:58 UTC (rev 184933)
@@ -2066,31 +2066,58 @@
 void SpeculativeJIT::compileDoubleRep(Node* node)
 {
     switch (node->child1().useKind()) {
+    case NotCellUse:
     case NumberUse: {
         ASSERT(!node->child1()->isNumberConstant()); // This should have been constant folded.
-    
-        if (isInt32Speculation(m_state.forNode(node->child1()).m_type)) {
+
+        SpeculatedType possibleTypes = m_state.forNode(node->child1()).m_type;
+        if (isInt32Speculation(possibleTypes)) {
             SpeculateInt32Operand op1(this, node->child1(), ManualOperandSpeculation);
             FPRTemporary result(this);
             m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
             doubleResult(result.fpr(), node);
             return;
         }
-    
+
         JSValueOperand op1(this, node->child1(), ManualOperandSpeculation);
         FPRTemporary result(this);
-    
+
 #if USE(JSVALUE64)
         GPRTemporary temp(this);
 
         GPRReg op1GPR = op1.gpr();
         GPRReg tempGPR = temp.gpr();
         FPRReg resultFPR = result.fpr();
-    
+        JITCompiler::JumpList done;
+
         JITCompiler::Jump isInteger = m_jit.branch64(
             MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister);
-    
-        if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) {
+
+        if (node->child1().useKind() == NotCellUse) {
+            JITCompiler::Jump isNumber = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagTypeNumberRegister);
+            JITCompiler::Jump isUndefined = m_jit.branch64(JITCompiler::Equal, op1GPR, TrustedImm64(ValueUndefined));
+
+            static const double zero = 0;
+            m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&zero), resultFPR);
+
+            JITCompiler::Jump isNull = m_jit.branch64(JITCompiler::Equal, op1GPR, TrustedImm64(ValueNull));
+            done.append(isNull);
+
+            DFG_TYPE_CHECK(JSValueRegs(op1GPR), node->child1(), ~SpecCell,
+                m_jit.branchTest64(JITCompiler::NonZero, op1GPR, TrustedImm32(static_cast<int32_t>(~1))));
+
+            JITCompiler::Jump isFalse = m_jit.branch64(JITCompiler::Equal, op1GPR, TrustedImm64(ValueFalse));
+            static const double _one_ = 1;
+            m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&one), resultFPR);
+            done.append(isFalse);
+
+            isUndefined.link(&m_jit);
+            static const double NaN = PNaN;
+            m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&NaN), resultFPR);
+            done.append(m_jit.jump());
+
+            isNumber.link(&m_jit);
+        } else if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) {
             typeCheck(
                 JSValueRegs(op1GPR), node->child1(), SpecBytecodeNumber,
                 m_jit.branchTest64(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister));
@@ -2098,7 +2125,7 @@
     
         m_jit.move(op1GPR, tempGPR);
         unboxDouble(tempGPR, resultFPR);
-        JITCompiler::Jump done = m_jit.jump();
+        done.append(m_jit.jump());
     
         isInteger.link(&m_jit);
         m_jit.convertInt32ToDouble(op1GPR, resultFPR);
@@ -2110,18 +2137,42 @@
         GPRReg op1PayloadGPR = op1.payloadGPR();
         FPRReg tempFPR = temp.fpr();
         FPRReg resultFPR = result.fpr();
+        JITCompiler::JumpList done;
     
         JITCompiler::Jump isInteger = m_jit.branch32(
             MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag));
-    
-        if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) {
+
+        if (node->child1().useKind() == NotCellUse) {
+            JITCompiler::Jump isNumber = m_jit.branch32(JITCompiler::Below, op1TagGPR, JITCompiler::TrustedImm32(JSValue::LowestTag + 1));
+            JITCompiler::Jump isUndefined = m_jit.branch32(JITCompiler::Equal, op1TagGPR, TrustedImm32(JSValue::UndefinedTag));
+
+            static const double zero = 0;
+            m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&zero), resultFPR);
+
+            JITCompiler::Jump isNull = m_jit.branch32(JITCompiler::Equal, op1TagGPR, TrustedImm32(JSValue::NullTag));
+            done.append(isNull);
+
+            DFG_TYPE_CHECK(JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), ~SpecCell, m_jit.branch32(JITCompiler::NotEqual, op1TagGPR, TrustedImm32(JSValue::BooleanTag)));
+
+            JITCompiler::Jump isFalse = m_jit.branchTest32(JITCompiler::Zero, op1PayloadGPR, TrustedImm32(1));
+            static const double _one_ = 1;
+            m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&one), resultFPR);
+            done.append(isFalse);
+
+            isUndefined.link(&m_jit);
+            static const double NaN = PNaN;
+            m_jit.loadDouble(MacroAssembler::TrustedImmPtr(&NaN), resultFPR);
+            done.append(m_jit.jump());
+
+            isNumber.link(&m_jit);
+        } else if (needsTypeCheck(node->child1(), SpecBytecodeNumber)) {
             typeCheck(
                 JSValueRegs(op1TagGPR, op1PayloadGPR), node->child1(), SpecBytecodeNumber,
                 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
         }
-    
+
         unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR);
-        JITCompiler::Jump done = m_jit.jump();
+        done.append(m_jit.jump());
     
         isInteger.link(&m_jit);
         m_jit.convertInt32ToDouble(op1PayloadGPR, resultFPR);

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (184932 => 184933)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-05-28 00:39:35 UTC (rev 184932)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-05-28 01:30:58 UTC (rev 184933)
@@ -958,9 +958,12 @@
     void compileDoubleRep()
     {
         switch (m_node->child1().useKind()) {
+        case NotCellUse:
         case NumberUse: {
+            bool shouldConvertNonNumber = m_node->child1().useKind() == NotCellUse;
+
             LValue value = lowJSValue(m_node->child1(), ManualOperandSpeculation);
-            setDouble(jsValueToDouble(m_node->child1(), value));
+            setDouble(jsValueToDouble(m_node->child1(), value, shouldConvertNonNumber));
             return;
         }
             
@@ -7199,10 +7202,12 @@
     {
         return m_out.sub(m_out.bitCast(doubleValue, m_out.int64), m_tagTypeNumber);
     }
-    LValue jsValueToDouble(Edge edge, LValue boxedValue)
+    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;
@@ -7212,24 +7217,70 @@
             isNotInt32 = m_out.booleanTrue;
         else
             isNotInt32 = this->isNotInt32(boxedValue);
-        m_out.branch(isNotInt32, unsure(doubleCase), unsure(intCase));
+        m_out.branch(isNotInt32, unsure(doubleTesting), unsure(intCase));
             
-        LBasicBlock lastNext = m_out.appendTo(intCase, doubleCase);
+        LBasicBlock lastNext = m_out.appendTo(intCase, doubleTesting);
             
         ValueFromBlock intToDouble = m_out.anchor(
             m_out.intToDouble(unboxInt32(boxedValue)));
         m_out.jump(continuation);
             
-        m_out.appendTo(doubleCase, continuation);
-            
-        FTL_TYPE_CHECK(
-            jsValueValue(boxedValue), edge, SpecBytecodeNumber, isCellOrMisc(boxedValue));
-            
+        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);
     }
     

Added: trunk/Source/_javascript_Core/tests/stress/double-rep-with-non-cell.js (0 => 184933)


--- trunk/Source/_javascript_Core/tests/stress/double-rep-with-non-cell.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/double-rep-with-non-cell.js	2015-05-28 01:30:58 UTC (rev 184933)
@@ -0,0 +1,32 @@
+// Only bool, undefined and null
+function addNullBoolUndefined(a, b) {
+    return a + b;
+}
+noInline(addNullBoolUndefined);
+
+for (var i = 0; i < 1e7; ++i) {
+    var value = addNullBoolUndefined(0.5, null);
+    if (value !== 0.5)
+        throw "addNullBoolUndefined(0.5, null) failed with i = " + i + " returned value = " + value;
+
+    var value = addNullBoolUndefined(null, undefined);
+    if (value === value)
+        throw "addNullBoolUndefined(null, undefined) failed with i = " + i + " returned value = " + value;
+
+    var value = addNullBoolUndefined(true, null);
+    if (value !== 1)
+        throw "addNullBoolUndefined(true, null) failed with i = " + i + " returned value = " + value;
+
+    var value = addNullBoolUndefined(undefined, false);
+    if (value === value)
+        throw "addNullBoolUndefined(undefined, false) failed with i = " + i + " returned value = " + value;
+
+    var value = addNullBoolUndefined(false, true);
+    if (value !== 1)
+        throw "addNullBoolUndefined(false, true) failed with i = " + i + " returned value = " + value;
+
+    var value = addNullBoolUndefined(null, 42);
+    if (value !== 42)
+        throw "addNullBoolUndefined(null, 42) failed with i = " + i + " returned value = " + value;
+
+}

Added: trunk/Source/_javascript_Core/tests/stress/double-rep-with-null.js (0 => 184933)


--- trunk/Source/_javascript_Core/tests/stress/double-rep-with-null.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/double-rep-with-null.js	2015-05-28 01:30:58 UTC (rev 184933)
@@ -0,0 +1,107 @@
+// Using full number + null for math.
+function addArgsNumberAndNull(a, b) {
+    return a + b;
+}
+noInline(addArgsNumberAndNull);
+
+for (var i = 0; i < 1e7; ++i) {
+    var value = addArgsNumberAndNull(i, 1);
+    if (value !== (i + 1))
+        throw "addArgsNumberAndNull(i, 1) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndNull(0.5, i);
+    if (value !== (i + 0.5))
+        throw "addArgsNumberAndNull(0.5, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndNull(null, i);
+    if (value !== i)
+        throw "addArgsNumberAndNull(null, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndNull(i, null);
+    if (value !== i)
+        throw "addArgsNumberAndNull(i, null) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndNull(null, null);
+    if (value !== 0)
+        throw "addArgsNumberAndNull(null, null) failed with i = " + i + " returned value = " + value;
+}
+
+
+// Using int32 + null for math.
+function addArgsInt32AndNull(a, b) {
+    return a + b;
+}
+noInline(addArgsInt32AndNull);
+
+for (var i = 0; i < 1e7; ++i) {
+    var value = addArgsInt32AndNull(i, 1);
+    if (value !== (i + 1))
+        throw "addArgsInt32AndNull(i, 1) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsInt32AndNull(null, i);
+    if (value !== i)
+        throw "addArgsInt32AndNull(null, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsInt32AndNull(i, null);
+    if (value !== i)
+        throw "addArgsInt32AndNull(i, null) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsInt32AndNull(null, null);
+    if (value !== 0)
+        throw "addArgsInt32AndNull(null, null) failed with i = " + i + " returned value = " + value;
+}
+
+function testFallbackWithDouble() {
+    var value = addArgsNumberAndNull(Math.PI, Math.PI);
+    if (value !== 2 * Math.PI)
+        throw "addArgsNumberAndNull(Math.PI, Math.PI) failed with i = " + i + " returned value = " + value;
+}
+testFallbackWithDouble();
+
+
+// Using full number + null for math.
+function addArgsDoubleAndNull(a, b) {
+    return a + b;
+}
+noInline(addArgsDoubleAndNull);
+
+for (var i = 0; i < 1e7; ++i) {
+    var value = addArgsDoubleAndNull(0.5, i);
+    if (value !== (i + 0.5))
+        throw "addArgsDoubleAndNull(0.5, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsDoubleAndNull(null, 0.1);
+    if (value !== 0.1)
+        throw "addArgsDoubleAndNull(null, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsDoubleAndNull(0.6, null);
+    if (value !== 0.6)
+        throw "addArgsDoubleAndNull(i, null) failed with i = " + i + " returned value = " + value;
+}
+
+function testFallbackWithObject() {
+    var value = addArgsDoubleAndNull(Math.PI, { valueOf: function() { return 5; }});
+    if (value !== 5 + Math.PI)
+        throw "addArgsDoubleAndNull(Math.PI, { valueOf: function() { return 5; }}) failed with i = " + i + " returned value = " + value;
+}
+testFallbackWithObject();
+
+
+// Using only null
+function addArgsOnlyNull(a, b) {
+    return a + b;
+}
+noInline(addArgsOnlyNull);
+
+for (var i = 0; i < 1e7; ++i) {
+    var value = addArgsOnlyNull(null, null);
+    if (value !== 0)
+        throw "addArgsOnlyNull(null, null) failed with i = " + i + " returned value = " + value;
+}
+
+function testFallbackWithString() {
+    var value = addArgsOnlyNull("foo", "bar");
+    if (value !== "foobar")
+        throw "addArgsOnlyNull(\"foo\", \"bar\") failed with i = " + i + " returned value = " + value;
+}
+testFallbackWithString();
\ No newline at end of file

Added: trunk/Source/_javascript_Core/tests/stress/double-rep-with-undefined.js (0 => 184933)


--- trunk/Source/_javascript_Core/tests/stress/double-rep-with-undefined.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/double-rep-with-undefined.js	2015-05-28 01:30:58 UTC (rev 184933)
@@ -0,0 +1,131 @@
+// Using full number + undefined for math.
+function addArgsNumberAndUndefined(a, b) {
+    return a + b;
+}
+noInline(addArgsNumberAndUndefined);
+
+for (var i = 0; i < 1e7; ++i) {
+    var value = addArgsNumberAndUndefined(i, 1);
+    if (value !== (i + 1))
+        throw "addArgsNumberAndUndefined(i, 1) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndUndefined(0.5, i);
+    if (value !== (i + 0.5))
+        throw "addArgsNumberAndUndefined(0.5, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndUndefined(undefined, i);
+    if (value === value)
+        throw "addArgsNumberAndUndefined(undefined, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndUndefined(i, undefined);
+    if (value === value)
+        throw "addArgsNumberAndUndefined(i, undefined) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndUndefined(i);
+    if (value === value)
+        throw "addArgsNumberAndUndefined(i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndUndefined(undefined, undefined);
+    if (value === value)
+        throw "addArgsNumberAndUndefined(undefined, undefined) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsNumberAndUndefined();
+    if (value === value)
+        throw "addArgsNumberAndUndefined() failed with i = " + i + " returned value = " + value;
+}
+
+
+// Using int32 + undefined for math.
+function addArgsInt32AndUndefined(a, b) {
+    return a + b;
+}
+noInline(addArgsInt32AndUndefined);
+
+for (var i = 0; i < 1e7; ++i) {
+    var value = addArgsInt32AndUndefined(i, 1);
+    if (value !== (i + 1))
+        throw "addArgsInt32AndUndefined(i, 1) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsInt32AndUndefined(undefined, i);
+    if (value === value)
+        throw "addArgsInt32AndUndefined(undefined, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsInt32AndUndefined(i, undefined);
+    if (value === value)
+        throw "addArgsInt32AndUndefined(i, undefined) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsInt32AndUndefined(i);
+    if (value === value)
+        throw "addArgsInt32AndUndefined(i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsInt32AndUndefined(undefined, undefined);
+    if (value === value)
+        throw "addArgsInt32AndUndefined(undefined, undefined) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsInt32AndUndefined();
+    if (value === value)
+        throw "addArgsInt32AndUndefined() failed with i = " + i + " returned value = " + value;
+}
+
+function testFallbackWithDouble() {
+    var value = addArgsNumberAndUndefined(Math.PI, Math.PI);
+    if (value !== 2 * Math.PI)
+        throw "addArgsNumberAndUndefined(Math.PI, Math.PI) failed with i = " + i + " returned value = " + value;
+}
+testFallbackWithDouble();
+
+
+// Using full number + undefined for math.
+function addArgsDoubleAndUndefined(a, b) {
+    return a + b;
+}
+noInline(addArgsDoubleAndUndefined);
+
+for (var i = 0; i < 1e7; ++i) {
+    var value = addArgsDoubleAndUndefined(0.5, i);
+    if (value !== (i + 0.5))
+        throw "addArgsDoubleAndUndefined(0.5, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsDoubleAndUndefined(undefined, 0.1);
+    if (value === value)
+        throw "addArgsDoubleAndUndefined(undefined, i) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsDoubleAndUndefined(0.6, undefined);
+    if (value === value)
+        throw "addArgsDoubleAndUndefined(i, undefined) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsDoubleAndUndefined(42.8);
+    if (value === value)
+        throw "addArgsDoubleAndUndefined(i) failed with i = " + i + " returned value = " + value;
+}
+
+function testFallbackWithObject() {
+    var value = addArgsDoubleAndUndefined(Math.PI, { valueOf: function() { return 5; }});
+    if (value !== 5 + Math.PI)
+        throw "addArgsDoubleAndUndefined(Math.PI, { valueOf: function() { return 5; }}) failed with i = " + i + " returned value = " + value;
+}
+testFallbackWithObject();
+
+
+// Using full number + undefined for math.
+function addArgsOnlyUndefined(a, b) {
+    return a + b;
+}
+noInline(addArgsOnlyUndefined);
+
+for (var i = 0; i < 1e7; ++i) {
+    var value = addArgsOnlyUndefined(undefined, undefined);
+    if (value === value)
+        throw "addArgsOnlyUndefined(undefined, undefined) failed with i = " + i + " returned value = " + value;
+
+    var value = addArgsOnlyUndefined();
+    if (value === value)
+        throw "addArgsOnlyUndefined() failed with i = " + i + " returned value = " + value;
+}
+
+function testFallbackWithString() {
+    var value = addArgsOnlyUndefined("foo", "bar");
+    if (value !== "foobar")
+        throw "addArgsOnlyUndefined(\"foo\", \"bar\") failed with i = " + i + " returned value = " + value;
+}
+testFallbackWithString();
\ No newline at end of file
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to