Title: [231224] trunk
Revision
231224
Author
[email protected]
Date
2018-05-01 22:51:33 -0700 (Tue, 01 May 2018)

Log Message

[JSC] Add SameValue DFG node
https://bugs.webkit.org/show_bug.cgi?id=185065

Reviewed by Saam Barati.

JSTests:

* microbenchmarks/object-is.js: Added.
(incognito):
(sameValue):
(test1):
(test2):
(test3):
(test4):
(test5):
(test6):
* stress/object-is.js: Added.
(shouldBe):
(is1):
(is2):
(is3):
(is4):
(is5):
(is6):
(is7):
(is8):
(is9):
(is10):
(is11):
(is12):
(is13):
(is14):
(is15):

Source/_javascript_Core:

This patch adds Object.is handling in DFG and FTL. Object.is is converted to SameValue DFG node.
And DFG fixup phase attempts to convert SameValue node to CompareStrictEq with type filter edges
if possible. Since SameValue(Untyped, Untyped) and SameValue(Double, Double) have different semantics
from CompareStrictEq, we do not convert SameValue to CompareStrictEq for them. DFG and FTL have
implementations for these SameValue nodes.

This old MacroAssemblerX86Common::compareDouble was dead code since the derived class, "MacroAssembler"
has a generalized compareDouble, which just uses branchDouble. Since this was not used, this function
was broken. This patch fixes issues and move compareDouble to MacroAssemblerX86Common, and remove a
generalized compareDouble for x86 arch to use this specialized efficient version instead. The fixes are
correctly using set32 to zero-extending the result, and setting the initial value of `dest` register
correctly for DoubleEqual and DoubleNotEqualOrUnordered cases.

Added microbenchmark shows performance improvement.

    object-is           651.0053+-38.8204    ^    241.3467+-15.8753       ^ definitely 2.6974x faster

* assembler/MacroAssembler.h:
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::compareDouble):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::compareDouble): Deleted.
* assembler/testmasm.cpp:
(JSC::doubleOperands):
(JSC::testCompareDouble):
(JSC::run):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupCompareStrictEqAndSameValue):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileSameValue):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileSameValue):
* runtime/Intrinsic.cpp:
(JSC::intrinsicName):
* runtime/Intrinsic.h:
* runtime/ObjectConstructor.cpp:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (231223 => 231224)


--- trunk/JSTests/ChangeLog	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/JSTests/ChangeLog	2018-05-02 05:51:33 UTC (rev 231224)
@@ -1,3 +1,37 @@
+2018-05-01  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Add SameValue DFG node
+        https://bugs.webkit.org/show_bug.cgi?id=185065
+
+        Reviewed by Saam Barati.
+
+        * microbenchmarks/object-is.js: Added.
+        (incognito):
+        (sameValue):
+        (test1):
+        (test2):
+        (test3):
+        (test4):
+        (test5):
+        (test6):
+        * stress/object-is.js: Added.
+        (shouldBe):
+        (is1):
+        (is2):
+        (is3):
+        (is4):
+        (is5):
+        (is6):
+        (is7):
+        (is8):
+        (is9):
+        (is10):
+        (is11):
+        (is12):
+        (is13):
+        (is14):
+        (is15):
+
 2018-05-01  Robin Morisset  <[email protected]>
 
         Correctly detect string overflow when using the 'Function' constructor

Added: trunk/JSTests/microbenchmarks/object-is.js (0 => 231224)


--- trunk/JSTests/microbenchmarks/object-is.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/object-is.js	2018-05-02 05:51:33 UTC (rev 231224)
@@ -0,0 +1,82 @@
+function incognito(value) {
+    var array = [];
+    array.push(value);
+    array.push("ignore me");
+    array.push(value);
+    array.push({ ignore: "me" });
+    return array[((Math.random() * 2) | 0) * 2];
+}
+
+// cached Object.is
+var objectIs = Object.is;
+
+// pure JS version of Object.is
+function sameValue(a, b) {
+    return (a === b) ?
+        (a !== 0 || (1 / a === 1 / b)) :
+        (a !== a && b !== b);
+}
+
+var testFiveA = incognito("back5");
+var testFiveB = incognito("2back5".substring(1));
+var testPi = incognito("PI");
+var testNaN = incognito(NaN);
+var testNaN_2 = incognito(NaN);
+
+var result;
+
+function test1()
+{
+    return testFiveA === testFiveB;
+}
+noInline(test1);
+
+function test2()
+{
+    return Object.is(testFiveA, testFiveB);
+}
+noInline(test2);
+
+function test3()
+{
+    return sameValue(testFiveA, testFiveB);
+}
+noInline(test3);
+
+function test4()
+{
+    return testFiveA === testPi;
+}
+noInline(test4);
+
+function test5()
+{
+    return Object.is(testFiveA, testPi);
+}
+noInline(test5);
+
+function test6()
+{
+    return sameValue(testFiveA, testPi);
+}
+noInline(test6);
+
+var verbose = false;
+var tests = [
+//     test1,
+    test2,
+//     test3,
+//     test4,
+    test5,
+//     test6,
+];
+for (let test of tests) {
+    if (verbose)
+        var time = Date.now();
+
+    for (let i = 0; i < 2e7; ++i)
+        test();
+
+    if (verbose)
+        print(Date.now() - time);
+}

Added: trunk/JSTests/stress/object-is.js (0 => 231224)


--- trunk/JSTests/stress/object-is.js	                        (rev 0)
+++ trunk/JSTests/stress/object-is.js	2018-05-02 05:51:33 UTC (rev 231224)
@@ -0,0 +1,72 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function is1(a, b) { return Object.is(a, b); }
+noInline(is1);
+function is2(a, b) { return Object.is(a, b); }
+noInline(is2);
+function is3(a, b) { return Object.is(a, b); }
+noInline(is3);
+function is4(a, b) { return Object.is(a, b); }
+noInline(is4);
+function is5(a, b) { return Object.is(a, b); }
+noInline(is5);
+function is6(a, b) { return Object.is(a, b); }
+noInline(is6);
+function is7(a, b) { return Object.is(a, b); }
+noInline(is7);
+function is8(a, b) { return Object.is(a, b); }
+noInline(is8);
+function is9(a, b) { return Object.is(a, b); }
+noInline(is9);
+function is10(a, b) { return Object.is(a, b); }
+noInline(is10);
+function is11(a, b) { return Object.is(a, b); }
+noInline(is11);
+function is12(a, b) { return Object.is(a, b); }
+noInline(is12);
+function is13(a, b) { return Object.is(a, b); }
+noInline(is13);
+function is14(a, b) { return Object.is(a, b); }
+noInline(is14);
+function is15(a, b) { return Object.is(a, b); }
+noInline(is15);
+
+for (var i = 0; i < 1e5; ++i) {
+    shouldBe(Object.is(NaN, NaN), true);
+    shouldBe(Object.is(null, null), true);
+    shouldBe(Object.is(null), false);
+    shouldBe(Object.is(undefined, undefined), true);
+    shouldBe(Object.is(true, true), true);
+    shouldBe(Object.is(false, false), true);
+    shouldBe(Object.is('abc', 'abc'), true);
+    shouldBe(Object.is(Infinity, Infinity), true);
+    shouldBe(Object.is(0, 0), true);
+    shouldBe(Object.is(-0, -0), true);
+    shouldBe(Object.is(0, -0), false);
+    shouldBe(Object.is(-0, 0), false);
+    var obj = {};
+    shouldBe(Object.is(obj, obj), true);
+    var arr = [];
+    shouldBe(Object.is(arr, arr), true);
+    var sym = Symbol();
+    shouldBe(Object.is(sym, sym), true);
+
+    shouldBe(is1(NaN, NaN), true);
+    shouldBe(is2(null, null), true);
+    shouldBe(is3(null), false);
+    shouldBe(is4(undefined, undefined), true);
+    shouldBe(is5(true, true), true);
+    shouldBe(is6(false, false), true);
+    shouldBe(is7('abc', 'abc'), true);
+    shouldBe(is8(Infinity, Infinity), true);
+    shouldBe(is9(0, 0), true);
+    shouldBe(is10(-0, -0), true);
+    shouldBe(is11(0, -0), false);
+    shouldBe(is12(-0, 0), false);
+    shouldBe(is13(obj, obj), true);
+    shouldBe(is14(arr, arr), true);
+    shouldBe(is15(sym, sym), true);
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (231223 => 231224)


--- trunk/Source/_javascript_Core/ChangeLog	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-05-02 05:51:33 UTC (rev 231224)
@@ -1,3 +1,73 @@
+2018-05-01  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Add SameValue DFG node
+        https://bugs.webkit.org/show_bug.cgi?id=185065
+
+        Reviewed by Saam Barati.
+
+        This patch adds Object.is handling in DFG and FTL. Object.is is converted to SameValue DFG node.
+        And DFG fixup phase attempts to convert SameValue node to CompareStrictEq with type filter edges
+        if possible. Since SameValue(Untyped, Untyped) and SameValue(Double, Double) have different semantics
+        from CompareStrictEq, we do not convert SameValue to CompareStrictEq for them. DFG and FTL have
+        implementations for these SameValue nodes.
+
+        This old MacroAssemblerX86Common::compareDouble was dead code since the derived class, "MacroAssembler"
+        has a generalized compareDouble, which just uses branchDouble. Since this was not used, this function
+        was broken. This patch fixes issues and move compareDouble to MacroAssemblerX86Common, and remove a
+        generalized compareDouble for x86 arch to use this specialized efficient version instead. The fixes are
+        correctly using set32 to zero-extending the result, and setting the initial value of `dest` register
+        correctly for DoubleEqual and DoubleNotEqualOrUnordered cases.
+
+        Added microbenchmark shows performance improvement.
+
+            object-is           651.0053+-38.8204    ^    241.3467+-15.8753       ^ definitely 2.6974x faster
+
+        * assembler/MacroAssembler.h:
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::compareDouble):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::compareDouble): Deleted.
+        * assembler/testmasm.cpp:
+        (JSC::doubleOperands):
+        (JSC::testCompareDouble):
+        (JSC::run):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixupCompareStrictEqAndSameValue):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileSameValue):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValidate.cpp:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileSameValue):
+        * runtime/Intrinsic.cpp:
+        (JSC::intrinsicName):
+        * runtime/Intrinsic.h:
+        * runtime/ObjectConstructor.cpp:
+
 2018-04-30  Filip Pizlo  <[email protected]>
 
         B3::demoteValues should be able to handle patchpoint terminals

Modified: trunk/Source/_javascript_Core/assembler/MacroAssembler.h (231223 => 231224)


--- trunk/Source/_javascript_Core/assembler/MacroAssembler.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/assembler/MacroAssembler.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -1459,9 +1459,10 @@
 
 #endif // !CPU(X86_64)
 
-#if ENABLE(B3_JIT)
     // We should implement this the right way eventually, but for now, it's fine because it arises so
     // infrequently.
+
+#if !CPU(X86) && !CPU(X86_64)
     void compareDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest)
     {
         move(TrustedImm32(0), dest);
@@ -1469,6 +1470,9 @@
         move(TrustedImm32(1), dest);
         falseCase.link(this);
     }
+#endif
+
+#if ENABLE(B3_JIT)
     void compareFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest)
     {
         move(TrustedImm32(0), dest);

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (231223 => 231224)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -2014,6 +2014,48 @@
         return jumpAfterFloatingPointCompare(cond, left, right);
     }
 
+    void compareDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest)
+    {
+        if (cond & DoubleConditionBitSpecial) {
+            ASSERT(!(cond & DoubleConditionBitInvert));
+            if (cond == DoubleEqual) {
+                if (left == right) {
+                    m_assembler.ucomisd_rr(right, left);
+                    set32(X86Assembler::ConditionNP, dest);
+                    return;
+                }
+
+                move(TrustedImm32(0), dest);
+                m_assembler.ucomisd_rr(right, left);
+                Jump isUnordered = m_assembler.jp();
+                set32(X86Assembler::ConditionE, dest);
+                isUnordered.link(this);
+                return;
+            }
+            if (cond == DoubleNotEqualOrUnordered) {
+                if (left == right) {
+                    m_assembler.ucomisd_rr(right, left);
+                    set32(X86Assembler::ConditionP, dest);
+                    return;
+                }
+
+                move(TrustedImm32(1), dest);
+                m_assembler.ucomisd_rr(right, left);
+                Jump isUnordered = m_assembler.jp();
+                set32(X86Assembler::ConditionNE, dest);
+                isUnordered.link(this);
+                return;
+            }
+            return;
+        }
+
+        if (cond & DoubleConditionBitInvert)
+            m_assembler.ucomisd_rr(left, right);
+        else
+            m_assembler.ucomisd_rr(right, left);
+        set32(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits), dest);
+    }
+
     // Truncates 'src' to an integer, and places the resulting 'dest'.
     // If the result is not representable as a 32 bit value, branch.
     // May also branch for some values that are representable in 32 bits

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (231223 => 231224)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -983,40 +983,6 @@
         set32(x86Condition(cond), dest);
     }
 
-    void compareDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest)
-    {
-        if (cond & DoubleConditionBitInvert)
-            m_assembler.ucomisd_rr(left, right);
-        else
-            m_assembler.ucomisd_rr(right, left);
-
-        if (cond == DoubleEqual) {
-            if (left == right) {
-                m_assembler.setnp_r(dest);
-                return;
-            }
-
-            Jump isUnordered(m_assembler.jp());
-            m_assembler.sete_r(dest);
-            isUnordered.link(this);
-            return;
-        }
-
-        if (cond == DoubleNotEqualOrUnordered) {
-            if (left == right) {
-                m_assembler.setp_r(dest);
-                return;
-            }
-
-            m_assembler.setp_r(dest);
-            m_assembler.setne_r(dest);
-            return;
-        }
-
-        ASSERT(!(cond & DoubleConditionBitSpecial));
-        m_assembler.setCC_r(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits), dest);
-    }
-
     Jump branch64(RelationalCondition cond, RegisterID left, RegisterID right)
     {
         m_assembler.cmpq_rr(right, left);

Modified: trunk/Source/_javascript_Core/assembler/testmasm.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/assembler/testmasm.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/assembler/testmasm.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -227,6 +227,67 @@
 }
 
 
+static Vector<double> doubleOperands()
+{
+    return Vector<double> {
+        0,
+        -0,
+        1,
+        -1,
+        42,
+        -42,
+        std::numeric_limits<double>::max(),
+        std::numeric_limits<double>::min(),
+        std::numeric_limits<double>::lowest(),
+        std::numeric_limits<double>::quiet_NaN(),
+        std::numeric_limits<double>::infinity(),
+        -std::numeric_limits<double>::infinity(),
+    };
+}
+
+
+void testCompareDouble(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    double arg2 = 0;
+
+    auto compareDouble = compile([&, condition] (CCallHelpers& jit) {
+        jit.emitFunctionPrologue();
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.move(CCallHelpers::TrustedImm32(-1), GPRInfo::returnValueGPR);
+        jit.compareDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, GPRInfo::returnValueGPR);
+
+        jit.emitFunctionEpilogue();
+        jit.ret();
+    });
+
+    auto compareDoubleGeneric = compile([&, condition] (CCallHelpers& jit) {
+        jit.emitFunctionPrologue();
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
+        auto jump = jit.branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1);
+        jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
+        jump.link(&jit);
+
+        jit.emitFunctionEpilogue();
+        jit.ret();
+    });
+
+    auto operands = doubleOperands();
+    for (auto a : operands) {
+        for (auto b : operands) {
+            arg1 = a;
+            arg2 = b;
+            CHECK_EQ(invoke<int>(compareDouble), invoke<int>(compareDoubleGeneric));
+        }
+    }
+}
+
+
 #if ENABLE(MASM_PROBE)
 void testProbeReadsArgumentRegisters()
 {
@@ -787,6 +848,19 @@
     // reset to check a conversion result
     RUN(testBranchTruncateDoubleToInt32(123, 123));
 
+    RUN(testCompareDouble(MacroAssembler::DoubleEqual));
+    RUN(testCompareDouble(MacroAssembler::DoubleNotEqual));
+    RUN(testCompareDouble(MacroAssembler::DoubleGreaterThan));
+    RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrEqual));
+    RUN(testCompareDouble(MacroAssembler::DoubleLessThan));
+    RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrEqual));
+    RUN(testCompareDouble(MacroAssembler::DoubleEqualOrUnordered));
+    RUN(testCompareDouble(MacroAssembler::DoubleNotEqualOrUnordered));
+    RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrUnordered));
+    RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrEqualOrUnordered));
+    RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrUnordered));
+    RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered));
+
 #if ENABLE(MASM_PROBE)
     RUN(testProbeReadsArgumentRegisters());
     RUN(testProbeWritesArgumentRegisters());

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -1673,7 +1673,8 @@
         break;
     }
             
-    case CompareStrictEq: {
+    case CompareStrictEq:
+    case SameValue: {
         Node* leftNode = node->child1().node();
         Node* rightNode = node->child2().node();
         JSValue left = forNode(leftNode).value();
@@ -1689,7 +1690,10 @@
                     break;
                 }
             } else {
-                setConstant(node, jsBoolean(JSValue::strictEqual(0, left, right)));
+                if (node->op() == CompareStrictEq)
+                    setConstant(node, jsBoolean(JSValue::strictEqual(nullptr, left, right)));
+                else
+                    setConstant(node, jsBoolean(sameValue(nullptr, left, right)));
                 break;
             }
         }

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -2648,6 +2648,15 @@
         return true;
     }
 
+    case ObjectIsIntrinsic: {
+        if (argumentCountIncludingThis < 3)
+            return false;
+
+        insertChecks();
+        set(VirtualRegister(resultOperand), addToGraph(SameValue, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset))));
+        return true;
+    }
+
     case ReflectGetPrototypeOfIntrinsic: {
         if (argumentCountIncludingThis != 2)
             return false;

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -165,6 +165,7 @@
     case GetGlobalObject:
     case StringCharCodeAt:
     case CompareStrictEq:
+    case SameValue:
     case IsEmpty:
     case IsUndefined:
     case IsBoolean:

Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -140,7 +140,8 @@
                 break;
             }
 
-            case CompareStrictEq: {
+            case CompareStrictEq:
+            case SameValue: {
                 if (node->isBinaryUseKind(UntypedUse)) {
                     JSValue child1Constant = m_state.forNode(node->child1().node()).value();
                     JSValue child2Constant = m_state.forNode(node->child2().node()).value();

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -154,6 +154,7 @@
     case CompareEq:
     case CompareStrictEq:
     case CompareEqPtr:
+    case SameValue:
     case Call:
     case DirectCall:
     case TailCallInlinedCaller:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -589,106 +589,12 @@
             break;
         }
             
-        case CompareStrictEq: {
-            if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
-                fixEdge<BooleanUse>(node->child1());
-                fixEdge<BooleanUse>(node->child2());
-                break;
-            }
-            if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) {
-                fixEdge<Int32Use>(node->child1());
-                fixEdge<Int32Use>(node->child2());
-                break;
-            }
-            if (enableInt52()
-                && Node::shouldSpeculateAnyInt(node->child1().node(), node->child2().node())) {
-                fixEdge<Int52RepUse>(node->child1());
-                fixEdge<Int52RepUse>(node->child2());
-                break;
-            }
-            if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
-                fixEdge<DoubleRepUse>(node->child1());
-                fixEdge<DoubleRepUse>(node->child2());
-                break;
-            }
-            if (Node::shouldSpeculateSymbol(node->child1().node(), node->child2().node())) {
-                fixEdge<SymbolUse>(node->child1());
-                fixEdge<SymbolUse>(node->child2());
-                break;
-            }
-            if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) {
-                fixEdge<BigIntUse>(node->child1());
-                fixEdge<BigIntUse>(node->child2());
-                break;
-            }
-            if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
-                fixEdge<StringIdentUse>(node->child1());
-                fixEdge<StringIdentUse>(node->child2());
-                break;
-            }
-            if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 7) || isFTL(m_graph.m_plan.mode))) {
-                fixEdge<StringUse>(node->child1());
-                fixEdge<StringUse>(node->child2());
-                break;
-            }
-            WatchpointSet* masqueradesAsUndefinedWatchpoint = m_graph.globalObjectFor(node->origin.semantic)->masqueradesAsUndefinedWatchpoint();
-            if (masqueradesAsUndefinedWatchpoint->isStillValid()) {
-                
-                if (node->child1()->shouldSpeculateObject()) {
-                    m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
-                    fixEdge<ObjectUse>(node->child1());
-                    break;
-                }
-                if (node->child2()->shouldSpeculateObject()) {
-                    m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
-                    fixEdge<ObjectUse>(node->child2());
-                    break;
-                }
-                
-            } else if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
-                fixEdge<ObjectUse>(node->child1());
-                fixEdge<ObjectUse>(node->child2());
-                break;
-            }
-            if (node->child1()->shouldSpeculateSymbol()) {
-                fixEdge<SymbolUse>(node->child1());
-                break;
-            }
-            if (node->child2()->shouldSpeculateSymbol()) {
-                fixEdge<SymbolUse>(node->child2());
-                break;
-            }
-            if (node->child1()->shouldSpeculateMisc()) {
-                fixEdge<MiscUse>(node->child1());
-                break;
-            }
-            if (node->child2()->shouldSpeculateMisc()) {
-                fixEdge<MiscUse>(node->child2());
-                break;
-            }
-            if (node->child1()->shouldSpeculateStringIdent()
-                && node->child2()->shouldSpeculateNotStringVar()) {
-                fixEdge<StringIdentUse>(node->child1());
-                fixEdge<NotStringVarUse>(node->child2());
-                break;
-            }
-            if (node->child2()->shouldSpeculateStringIdent()
-                && node->child1()->shouldSpeculateNotStringVar()) {
-                fixEdge<StringIdentUse>(node->child2());
-                fixEdge<NotStringVarUse>(node->child1());
-                break;
-            }
-            if (node->child1()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
-                fixEdge<StringUse>(node->child1());
-                break;
-            }
-            if (node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
-                fixEdge<StringUse>(node->child2());
-                break;
-            }
+        case CompareStrictEq:
+        case SameValue: {
+            fixupCompareStrictEqAndSameValue(node);
             break;
         }
-            
+
         case StringFromCharCode:
             if (node->child1()->shouldSpeculateInt32()) {
                 fixEdge<Int32Use>(node->child1());
@@ -3478,6 +3384,138 @@
         }
     }
 
+    void fixupCompareStrictEqAndSameValue(Node* node)
+    {
+        ASSERT(node->op() == SameValue || node->op() == CompareStrictEq);
+
+        if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
+            fixEdge<BooleanUse>(node->child1());
+            fixEdge<BooleanUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) {
+            fixEdge<Int32Use>(node->child1());
+            fixEdge<Int32Use>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (enableInt52()
+            && Node::shouldSpeculateAnyInt(node->child1().node(), node->child2().node())) {
+            fixEdge<Int52RepUse>(node->child1());
+            fixEdge<Int52RepUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
+            fixEdge<DoubleRepUse>(node->child1());
+            fixEdge<DoubleRepUse>(node->child2());
+            // Do not convert SameValue to CompareStrictEq in this case since SameValue(NaN, NaN) and SameValue(-0, +0)
+            // are not the same to CompareStrictEq(NaN, NaN) and CompareStrictEq(-0, +0).
+            return;
+        }
+        if (Node::shouldSpeculateSymbol(node->child1().node(), node->child2().node())) {
+            fixEdge<SymbolUse>(node->child1());
+            fixEdge<SymbolUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) {
+            fixEdge<BigIntUse>(node->child1());
+            fixEdge<BigIntUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
+            fixEdge<StringIdentUse>(node->child1());
+            fixEdge<StringIdentUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child1()->shouldSpeculateString() && node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 7) || isFTL(m_graph.m_plan.mode))) {
+            fixEdge<StringUse>(node->child1());
+            fixEdge<StringUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+
+        if (node->op() == SameValue) {
+            if (node->child1()->shouldSpeculateObject()) {
+                fixEdge<ObjectUse>(node->child1());
+                node->setOpAndDefaultFlags(CompareStrictEq);
+                return;
+            }
+            if (node->child2()->shouldSpeculateObject()) {
+                fixEdge<ObjectUse>(node->child2());
+                node->setOpAndDefaultFlags(CompareStrictEq);
+                return;
+            }
+        } else {
+            WatchpointSet* masqueradesAsUndefinedWatchpoint = m_graph.globalObjectFor(node->origin.semantic)->masqueradesAsUndefinedWatchpoint();
+            if (masqueradesAsUndefinedWatchpoint->isStillValid()) {
+                if (node->child1()->shouldSpeculateObject()) {
+                    m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
+                    fixEdge<ObjectUse>(node->child1());
+                    return;
+                }
+                if (node->child2()->shouldSpeculateObject()) {
+                    m_graph.watchpoints().addLazily(masqueradesAsUndefinedWatchpoint);
+                    fixEdge<ObjectUse>(node->child2());
+                    return;
+                }
+            } else if (node->child1()->shouldSpeculateObject() && node->child2()->shouldSpeculateObject()) {
+                fixEdge<ObjectUse>(node->child1());
+                fixEdge<ObjectUse>(node->child2());
+                return;
+            }
+        }
+
+        if (node->child1()->shouldSpeculateSymbol()) {
+            fixEdge<SymbolUse>(node->child1());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child2()->shouldSpeculateSymbol()) {
+            fixEdge<SymbolUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child1()->shouldSpeculateMisc()) {
+            fixEdge<MiscUse>(node->child1());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child2()->shouldSpeculateMisc()) {
+            fixEdge<MiscUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child1()->shouldSpeculateStringIdent()
+            && node->child2()->shouldSpeculateNotStringVar()) {
+            fixEdge<StringIdentUse>(node->child1());
+            fixEdge<NotStringVarUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child2()->shouldSpeculateStringIdent()
+            && node->child1()->shouldSpeculateNotStringVar()) {
+            fixEdge<StringIdentUse>(node->child2());
+            fixEdge<NotStringVarUse>(node->child1());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child1()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
+            fixEdge<StringUse>(node->child1());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child2()->shouldSpeculateString() && ((GPRInfo::numberOfRegisters >= 8) || isFTL(m_graph.m_plan.mode))) {
+            fixEdge<StringUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+    }
+
     void fixupChecksInBlock(BasicBlock* block)
     {
         if (!block)

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -295,6 +295,7 @@
     macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \
     macro(CompareStrictEq, NodeResultBoolean) \
     macro(CompareEqPtr, NodeResultBoolean) \
+    macro(SameValue, NodeResultBoolean) \
     \
     /* Calls. */\
     macro(Call, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -1237,6 +1237,14 @@
     return JSValue::strictEqualSlowCaseInline(exec, op1, op2);
 }
 
+size_t JIT_OPERATION operationSameValue(ExecState* exec, EncodedJSValue arg1, EncodedJSValue arg2)
+{
+    VM& vm = exec->vm();
+    NativeCallFrameTracer tracer(&vm, exec);
+
+    return sameValue(exec, JSValue::decode(arg1), JSValue::decode(arg2));
+}
+
 EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
 {
     VM* vm = &exec->vm();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -161,6 +161,7 @@
 size_t JIT_OPERATION operationRegExpTest(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
 size_t JIT_OPERATION operationRegExpTestGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 size_t JIT_OPERATION operationCompareStrictEqCell(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+size_t JIT_OPERATION operationSameValue(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState*, Structure*, JSScope*, SymbolTable*, EncodedJSValue);
 JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState*, Structure*, uint32_t length, uint32_t minCapacity);
 JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState*, InlineCallFrame*, JSFunction*, uint32_t argumentCount);

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -851,6 +851,7 @@
         case CompareEq:
         case CompareStrictEq:
         case CompareEqPtr:
+        case SameValue:
         case OverridesHasInstance:
         case InstanceOf:
         case InstanceOfCustom:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -279,6 +279,7 @@
     case CompareEq:
     case CompareStrictEq:
     case CompareEqPtr:
+    case SameValue:
     case Call:
     case DirectCall:
     case TailCallInlinedCaller:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -6365,6 +6365,72 @@
     unblessedBooleanResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileSameValue(Node* node)
+{
+    if (node->isBinaryUseKind(DoubleRepUse)) {
+        SpeculateDoubleOperand arg1(this, node->child1());
+        SpeculateDoubleOperand arg2(this, node->child2());
+        GPRTemporary result(this);
+        GPRTemporary temp(this);
+        GPRTemporary temp2(this);
+
+        FPRReg arg1FPR = arg1.fpr();
+        FPRReg arg2FPR = arg2.fpr();
+        GPRReg resultGPR = result.gpr();
+        GPRReg tempGPR = temp.gpr();
+        GPRReg temp2GPR = temp2.gpr();
+
+#if USE(JSVALUE64)
+        m_jit.moveDoubleTo64(arg1FPR, tempGPR);
+        m_jit.moveDoubleTo64(arg2FPR, temp2GPR);
+        auto trueCase = m_jit.branch64(CCallHelpers::Equal, tempGPR, temp2GPR);
+#else
+        GPRTemporary temp3(this);
+        GPRTemporary temp4(this);
+
+        GPRReg temp3GPR = temp.gpr();
+        GPRReg temp4GPR = temp2.gpr();
+
+        m_jit.moveDoubleToInts(arg1FPR, tempGPR, temp2GPR);
+        m_jit.moveDoubleToInts(arg2FPR, temp3GPR, temp4GPR);
+        auto notEqual = m_jit.branch32(CCallHelpers::NotEqual, tempGPR, temp3GPR);
+        auto trueCase = m_jit.branch32(CCallHelpers::Equal, temp2GPR, temp4GPR);
+        notEqual.link(&m_jit);
+#endif
+
+        m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg1FPR, arg1FPR, tempGPR);
+        m_jit.compareDouble(CCallHelpers::DoubleNotEqualOrUnordered, arg2FPR, arg2FPR, temp2GPR);
+        m_jit.and32(tempGPR, temp2GPR, resultGPR);
+        auto done = m_jit.jump();
+
+        trueCase.link(&m_jit);
+        m_jit.move(CCallHelpers::TrustedImm32(1), resultGPR);
+        done.link(&m_jit);
+
+        unblessedBooleanResult(resultGPR, node);
+        return;
+    }
+
+    ASSERT(node->isBinaryUseKind(UntypedUse));
+
+    JSValueOperand arg1(this, node->child1());
+    JSValueOperand arg2(this, node->child2());
+    JSValueRegs arg1Regs = arg1.jsValueRegs();
+    JSValueRegs arg2Regs = arg2.jsValueRegs();
+
+    arg1.use();
+    arg2.use();
+
+    flushRegisters();
+
+    GPRFlushedCallResult result(this);
+    GPRReg resultGPR = result.gpr();
+    callOperation(operationSameValue, resultGPR, arg1Regs, arg2Regs);
+    m_jit.exceptionCheck();
+
+    unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
+}
+
 void SpeculativeJIT::compileStringZeroLength(Node* node)
 {
     SpeculateCellOperand str(this, node->child1());

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -1263,6 +1263,8 @@
     void compileStringIdentCompare(Node*, MacroAssembler::RelationalCondition);
     
     bool compileStrictEq(Node*);
+
+    void compileSameValue(Node*);
     
     void compileAllocatePropertyStorage(Node*);
     void compileReallocatePropertyStorage(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -2211,6 +2211,10 @@
         compileCompareEqPtr(node);
         break;
 
+    case SameValue:
+        compileSameValue(node);
+        break;
+
     case StringCharCodeAt: {
         compileGetCharCodeAt(node);
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -2377,6 +2377,10 @@
         compileCompareEqPtr(node);
         break;
 
+    case SameValue:
+        compileSameValue(node);
+        break;
+
     case StringCharCodeAt: {
         compileGetCharCodeAt(node);
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -271,6 +271,7 @@
                 case CompareBelowEq:
                 case CompareEq:
                 case CompareStrictEq:
+                case SameValue:
                 case StrCat:
                     VALIDATE((node), !!node->child1());
                     VALIDATE((node), !!node->child2());

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -314,6 +314,7 @@
     case CompareBelow:
     case CompareBelowEq:
     case CompareStrictEq:
+    case SameValue:
     case DefineDataProperty:
     case DefineAccessorProperty:
     case StringSlice:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -987,6 +987,9 @@
         case CompareEqPtr:
             compileCompareEqPtr();
             break;
+        case SameValue:
+            compileSameValue();
+            break;
         case LogicalNot:
             compileLogicalNot();
             break;
@@ -7072,6 +7075,45 @@
     {
         setBoolean(m_out.belowOrEqual(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
     }
+
+    void compileSameValue()
+    {
+        if (m_node->isBinaryUseKind(DoubleRepUse)) {
+            LValue arg1 = lowDouble(m_node->child1());
+            LValue arg2 = lowDouble(m_node->child2());
+
+            LBasicBlock numberCase = m_out.newBlock();
+            LBasicBlock continuation = m_out.newBlock();
+
+            PatchpointValue* patchpoint = m_out.patchpoint(Int32);
+            patchpoint->append(arg1, ValueRep::SomeRegister);
+            patchpoint->append(arg2, ValueRep::SomeRegister);
+            patchpoint->numGPScratchRegisters = 1;
+            patchpoint->setGenerator(
+                [] (CCallHelpers& jit, const StackmapGenerationParams& params) {
+                    GPRReg scratchGPR = params.gpScratch(0);
+                    jit.moveDoubleTo64(params[1].fpr(), scratchGPR);
+                    jit.moveDoubleTo64(params[2].fpr(), params[0].gpr());
+                    jit.compare64(CCallHelpers::Equal, scratchGPR, params[0].gpr(), params[0].gpr());
+                });
+            patchpoint->effects = Effects::none();
+            ValueFromBlock compareResult = m_out.anchor(patchpoint);
+            m_out.branch(patchpoint, unsure(continuation), unsure(numberCase));
+
+            LBasicBlock lastNext = m_out.appendTo(numberCase, continuation);
+            LValue isArg1NaN = m_out.doubleNotEqualOrUnordered(arg1, arg1);
+            LValue isArg2NaN = m_out.doubleNotEqualOrUnordered(arg2, arg2);
+            ValueFromBlock nanResult = m_out.anchor(m_out.bitAnd(isArg1NaN, isArg2NaN));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            setBoolean(m_out.phi(Int32, compareResult, nanResult));
+            return;
+        }
+
+        ASSERT(m_node->isBinaryUseKind(UntypedUse));
+        setBoolean(vmCall(Int32, m_out.operation(operationSameValue), m_callFrame, lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
+    }
     
     void compileLogicalNot()
     {

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -115,6 +115,8 @@
         return "RegExpMatchFastIntrinsic";
     case ObjectGetPrototypeOfIntrinsic:
         return "ObjectGetPrototypeOfIntrinsic";
+    case ObjectIsIntrinsic:
+        return "ObjectIsIntrinsic";
     case ReflectGetPrototypeOfIntrinsic:
         return "ReflectGetPrototypeOfIntrinsic";
     case StringPrototypeValueOfIntrinsic:

Modified: trunk/Source/_javascript_Core/runtime/Intrinsic.h (231223 => 231224)


--- trunk/Source/_javascript_Core/runtime/Intrinsic.h	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/runtime/Intrinsic.h	2018-05-02 05:51:33 UTC (rev 231224)
@@ -70,6 +70,7 @@
     RegExpTestFastIntrinsic,
     RegExpMatchFastIntrinsic,
     ObjectGetPrototypeOfIntrinsic,
+    ObjectIsIntrinsic,
     ReflectGetPrototypeOfIntrinsic,
     StringPrototypeValueOfIntrinsic,
     StringPrototypeReplaceIntrinsic,

Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (231223 => 231224)


--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2018-05-02 04:32:33 UTC (rev 231223)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp	2018-05-02 05:51:33 UTC (rev 231224)
@@ -83,7 +83,7 @@
   isSealed                  objectConstructorIsSealed                   DontEnum|Function 1
   isFrozen                  objectConstructorIsFrozen                   DontEnum|Function 1
   isExtensible              objectConstructorIsExtensible               DontEnum|Function 1
-  is                        objectConstructorIs                         DontEnum|Function 2
+  is                        objectConstructorIs                         DontEnum|Function 2 ObjectIsIntrinsic
   assign                    objectConstructorAssign                     DontEnum|Function 2
   values                    objectConstructorValues                     DontEnum|Function 1
   entries                   JSBuiltin                                   DontEnum|Function 1
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to