Title: [274037] trunk
Revision
274037
Author
[email protected]
Date
2021-03-06 06:42:37 -0800 (Sat, 06 Mar 2021)

Log Message

BooleanConstructor should be inlined in DFG / FTL
https://bugs.webkit.org/show_bug.cgi?id=220322

Reviewed by Yusuke Suzuki.

JSTests:

Reorganize tests so the every UseKind / needsTypeCheck / invert combination is covered.

* microbenchmarks/array-filter-boolean-constructor.js: Added.
* stress/dfg-branch.js: Added.
* stress/dfg-to-boolean.js: Added.
* stress/logical-not-masquerades-as-undefined.js: Removed.
* stress/logical-not-masquerades.js: Removed.
* stress/logical-not.js: Removed.
* stress/value-to-boolean.js: Removed.

Source/_javascript_Core:

`array.filter(Boolean)` is a rather popular idiom for removing falsy items from an array.
Also, `Boolean(X)` is sometimes used for explicit type casting.

This patch introduces ToBoolean DFG node and reorganizes compileLogicalNot(node) into
compileToBoolean(node, bool invert), leveraging already existing emitConvertValueToBoolean().

This approach is better than emitting LogicalNot<KnownBooleanUse>(LogicalNot(X)) as it results
in cleaner DFG node tree and is ~7% faster w/o FTL. Also, it enables adding a op_to_boolean
bytecode that will be generated for very common `!!X` patterns, reducing instruction count.

Just as LogicalNot, BooleanConstructor should handle masquerader objects, because Annex B
patches ToBoolean abstract op [1], preventing us from emitting simpler code.

This change advances provided microbenchmark by 110%, and is neutral for other ToBoolean cases.

[1]: https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-to-boolean

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGMayExit.cpp:
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileToBooleanString):
(JSC::DFG::SpeculativeJIT::compileToBooleanStringOrOther):
(JSC::DFG::SpeculativeJIT::compileStringZeroLength): Deleted.
(JSC::DFG::SpeculativeJIT::compileLogicalNotStringOrOther): Deleted.
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileToBooleanObjectOrOther):
(JSC::DFG::SpeculativeJIT::compileToBoolean):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): Deleted.
(JSC::DFG::SpeculativeJIT::compileLogicalNot): Deleted.
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileToBooleanObjectOrOther):
(JSC::DFG::SpeculativeJIT::compileToBoolean):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): Deleted.
(JSC::DFG::SpeculativeJIT::compileLogicalNot): Deleted.
* dfg/DFGWatchpointCollectionPhase.cpp:
(JSC::DFG::WatchpointCollectionPhase::handle):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileToBoolean):

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/JSTests/ChangeLog (274036 => 274037)


--- trunk/JSTests/ChangeLog	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/JSTests/ChangeLog	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1,3 +1,20 @@
+2021-03-06  Alexey Shvayka  <[email protected]>
+
+        BooleanConstructor should be inlined in DFG / FTL
+        https://bugs.webkit.org/show_bug.cgi?id=220322
+
+        Reviewed by Yusuke Suzuki.
+
+        Reorganize tests so the every UseKind / needsTypeCheck / invert combination is covered.
+
+        * microbenchmarks/array-filter-boolean-constructor.js: Added.
+        * stress/dfg-branch.js: Added.
+        * stress/dfg-to-boolean.js: Added.
+        * stress/logical-not-masquerades-as-undefined.js: Removed.
+        * stress/logical-not-masquerades.js: Removed.
+        * stress/logical-not.js: Removed.
+        * stress/value-to-boolean.js: Removed.
+
 2021-03-05  Tadeu Zagallo  <[email protected]>
 
         OpGetPrivateName needs to be listed in FOR_EACH_OPCODE_WITH_VALUE_PROFILE

Added: trunk/JSTests/microbenchmarks/array-filter-boolean-constructor.js (0 => 274037)


--- trunk/JSTests/microbenchmarks/array-filter-boolean-constructor.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/array-filter-boolean-constructor.js	2021-03-06 14:42:37 UTC (rev 274037)
@@ -0,0 +1,12 @@
+(function() {
+    var array = new Array(300);
+    for (var i = 0; i < 300; i++)
+        array[i] = i % 10;
+
+    var compacted;
+    for (var j = 0; j < 30000; j++)
+        compacted = array.filter(Boolean);
+
+    if (compacted.length !== 270)
+        throw new Error("Bad assert!");
+})();

Added: trunk/JSTests/stress/dfg-branch.js (0 => 274037)


--- trunk/JSTests/stress/dfg-branch.js	                        (rev 0)
+++ trunk/JSTests/stress/dfg-branch.js	2021-03-06 14:42:37 UTC (rev 274037)
@@ -0,0 +1,159 @@
+//@ if $buildType == "release" then runDefault else skip end
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`Bad value: ${actual}!`);
+}
+noInline(shouldBe);
+
+(function ObjectOrOtherUse() {
+    function test1(x) { if (x) return true; else return false; }
+    function test2(x) { return x ? true : false; }
+    function testInvert(x) { if (!x) return true; else return false; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1(undefined), false);
+        shouldBe(test1({}), true);
+        shouldBe(test2([]), true);
+        shouldBe(testInvert(new String("")), false);
+        shouldBe(testInvert(null), true);
+
+        shouldBe(test1(makeMasquerader()), false);
+        shouldBe(test2(makeMasquerader()), false);
+        shouldBe(testInvert(makeMasquerader()), true);
+    }
+})();
+
+(function Int32Use() {
+    function test1(x) { if (x) return true; else return false; }
+    function test2(x) { return x ? true : false; }
+    function testInvert(x) { if (!x) return true; else return false; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1(1), true);
+        shouldBe(test2(0), false);
+        shouldBe(test2(2147483647), true);
+        shouldBe(testInvert(-2147483648), false);
+    }
+})();
+
+(function DoubleRepUse() {
+    function test1(x) { if (x) return true; else return false; }
+    function test2(x) { return x ? true : false; }
+    function testInvert(x) { if (!x) return true; else return false; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1(0.5), true);
+        shouldBe(test1(-Infinity), true);
+        shouldBe(test2(-0), false);
+        shouldBe(testInvert(NaN), true);
+    }
+})();
+
+(function BooleanUse() {
+    function test1(x) { if (x) return true; else return false; }
+    function test2(x) { return x ? true : false; }
+    function testInvert(x) { if (!x) return true; else return false; }
+    function testTypeCheck(x) { return test1(x) ? true : false; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+    noInline(testTypeCheck);
+
+    for (let i = 0; i < 1e5; i++) {
+        // needsTypeCheck: false
+        shouldBe(test1(true), true);
+        shouldBe(test2(false), false);
+        shouldBe(testInvert(true), false);
+
+        // needsTypeCheck: true
+        shouldBe(testTypeCheck(true), true);
+    }
+})();
+
+(function UntypedUse() {
+    function test1(x) { if (x) return true; else return false; }
+    function test2(x) { return x ? true : false; }
+    function testInvert(x) { if (!x) return true; else return false; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    const testCases = [
+        [undefined, false],
+        [null, false],
+        [0, false],
+        [2147483647, true],
+        [false, false],
+        [true, true],
+        ["" + "" + "", false],
+        ["foo", true],
+        [-0, false],
+        [3.14, true],
+        [NaN, false],
+        [Infinity, true],
+        [Symbol(), true],
+        [{}, true],
+        [[], true],
+        [function() {}, true],
+        [makeMasquerader(), false],
+    ];
+
+    for (let i = 0; i < 1e5; i++) {
+        for (const [value, expected] of testCases) {
+            shouldBe(test1(value), expected);
+            shouldBe(test2(value), expected);
+            shouldBe(testInvert(value), !expected);
+        }
+    }
+})();
+
+(function StringUse() {
+    function test1(x) { if (x) return true; else return false; }
+    function test2(x) { return x ? true : false; }
+    function testInvert(x) { if (!x) return true; else return false; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1("\0"), true);
+        shouldBe(test2(""), false);
+        shouldBe(testInvert("" + "" + ""), true);
+        shouldBe(testInvert("foo" + "foo" + "foo"), false);
+    }
+})();
+
+(function StringOrOtherUse() {
+    function test1(x) { if (x) return true; else return false; }
+    function test2(x) { return x ? true : false; }
+    function testInvert(x) { if (!x) return true; else return false; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1("" + "" + ""), false);
+        shouldBe(test1(null), false);
+        shouldBe(test2("foo"), true);
+        shouldBe(test2(undefined), false);
+        shouldBe(testInvert(""), true);
+        shouldBe(testInvert(null), true);
+    }
+})();

Added: trunk/JSTests/stress/dfg-to-boolean.js (0 => 274037)


--- trunk/JSTests/stress/dfg-to-boolean.js	                        (rev 0)
+++ trunk/JSTests/stress/dfg-to-boolean.js	2021-03-06 14:42:37 UTC (rev 274037)
@@ -0,0 +1,159 @@
+//@ if $buildType == "release" then runDefault else skip end
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`Bad value: ${actual}!`);
+}
+noInline(shouldBe);
+
+(function ObjectOrOtherUse() {
+    function test1(x) { return !!x; }
+    function test2(x) { return Boolean(x); }
+    function testInvert(x) { return !x; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1(undefined), false);
+        shouldBe(test1({}), true);
+        shouldBe(test2([]), true);
+        shouldBe(testInvert(new String("")), false);
+        shouldBe(testInvert(null), true);
+
+        shouldBe(test1(makeMasquerader()), false);
+        shouldBe(test2(makeMasquerader()), false);
+        shouldBe(testInvert(makeMasquerader()), true);
+    }
+})();
+
+(function Int32Use() {
+    function test1(x) { return !!x; }
+    function test2(x) { return Boolean(x); }
+    function testInvert(x) { return !x; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1(1), true);
+        shouldBe(test2(0), false);
+        shouldBe(test2(2147483647), true);
+        shouldBe(testInvert(-2147483648), false);
+    }
+})();
+
+(function DoubleRepUse() {
+    function test1(x) { return !!x; }
+    function test2(x) { return Boolean(x); }
+    function testInvert(x) { return !x; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1(0.5), true);
+        shouldBe(test1(-Infinity), true);
+        shouldBe(test2(-0), false);
+        shouldBe(testInvert(NaN), true);
+    }
+})();
+
+(function BooleanUse() {
+    function test1(x) { return !!x; }
+    function test2(x) { return Boolean(x); }
+    function testInvert(x) { return !x; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        // needsTypeCheck: false
+        shouldBe(test1(true), true);
+        shouldBe(test2(false), false);
+        shouldBe(testInvert(true), false);
+
+        // needsTypeCheck: true
+        shouldBe(!test1(false), true);
+        shouldBe(Boolean(test2(true)), true);
+        shouldBe(!testInvert(false), false);
+    }
+})();
+
+(function UntypedUse() {
+    function test1(x) { return !!x; }
+    function test2(x) { return Boolean(x); }
+    function testInvert(x) { return !x; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    const testCases = [
+        [undefined, false],
+        [null, false],
+        [0, false],
+        [2147483647, true],
+        [false, false],
+        [true, true],
+        ["" + "" + "", false],
+        ["foo", true],
+        [-0, false],
+        [3.14, true],
+        [NaN, false],
+        [Infinity, true],
+        [Symbol(), true],
+        [{}, true],
+        [[], true],
+        [function() {}, true],
+        [makeMasquerader(), false],
+    ];
+
+    for (let i = 0; i < 1e5; i++) {
+        for (const [value, expected] of testCases) {
+            shouldBe(test1(value), expected);
+            shouldBe(test2(value), expected);
+            shouldBe(testInvert(value), !expected);
+        }
+    }
+})();
+
+(function StringUse() {
+    function test1(x) { return !!x; }
+    function test2(x) { return Boolean(x); }
+    function testInvert(x) { return !x; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1("\0"), true);
+        shouldBe(test2(""), false);
+        shouldBe(testInvert("" + "" + ""), true);
+        shouldBe(testInvert("foo" + "foo" + "foo"), false);
+    }
+})();
+
+(function StringOrOtherUse() {
+    function test1(x) { return !!x; }
+    function test2(x) { return Boolean(x); }
+    function testInvert(x) { return !x; }
+
+    noInline(test1);
+    noInline(test2);
+    noInline(testInvert);
+
+    for (let i = 0; i < 1e5; i++) {
+        shouldBe(test1("" + "" + ""), false);
+        shouldBe(test1(null), false);
+        shouldBe(test2("foo"), true);
+        shouldBe(test2(undefined), false);
+        shouldBe(testInvert(""), true);
+        shouldBe(testInvert(null), true);
+    }
+})();

Deleted: trunk/JSTests/stress/logical-not-masquerades-as-undefined.js (274036 => 274037)


--- trunk/JSTests/stress/logical-not-masquerades-as-undefined.js	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/JSTests/stress/logical-not-masquerades-as-undefined.js	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1,35 +0,0 @@
-function shouldBe(actual, expected) {
-    if (actual !== expected)
-        throw new Error('bad value: ' + actual);
-}
-
-function test(value)
-{
-    return !value;
-}
-noInline(test);
-
-var data = [
-    [ {}, true ],
-    [ true, true ],
-    [ false, false ],
-    [ -0, false ],
-    [ 1, true ],
-    [ 4.2, true ],
-    [ NaN, false ],
-    [ Infinity, true ],
-    [ [], true ],
-    [ new Date(), true ],
-    [ "", false ],
-    [ "" + "" + "", false ],
-    [ "Cocoa", true ],
-    [ undefined, false ],
-    [ null, false ],
-    [ Symbol(), true ],
-    [ makeMasquerader() , false]
-];
-
-for (var i = 0; i < 1e4; ++i) {
-    for (let [ value, result ] of data)
-        shouldBe(!test(value), result);
-}

Deleted: trunk/JSTests/stress/logical-not-masquerades.js (274036 => 274037)


--- trunk/JSTests/stress/logical-not-masquerades.js	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/JSTests/stress/logical-not-masquerades.js	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1,33 +0,0 @@
-function foo(value) {
-    return !!value;
-}
-
-noInline(foo);
-
-var tests = [
-    [0, false],
-    [1, true],
-    [0/0, false],
-    [0/-1, false],
-    [0.0, false],
-    ["", false],
-    ["f", true],
-    ["hello", true],
-    [{}, true],
-    [[], true],
-    [null, false],
-    [void 0, false],
-    [false, false],
-    [true, true],
-    [makeMasquerader(), false]
-];
-
-for (var i = 0; i < 10000; ++i) {
-    for (var j = 0; j < tests.length; ++j) {
-        var input = tests[j][0];
-        var expected = tests[j][1];
-        var result = foo(input);
-        if (result !== expected)
-            throw "Error: bad result for " + input + ": " + result;
-    }
-}

Deleted: trunk/JSTests/stress/logical-not.js (274036 => 274037)


--- trunk/JSTests/stress/logical-not.js	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/JSTests/stress/logical-not.js	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1,34 +0,0 @@
-function shouldBe(actual, expected) {
-    if (actual !== expected)
-        throw new Error('bad value: ' + actual);
-}
-
-function test(value)
-{
-    return !value;
-}
-noInline(test);
-
-var data = [
-    [ {}, true ],
-    [ true, true ],
-    [ false, false ],
-    [ -0, false ],
-    [ 1, true ],
-    [ 4.2, true ],
-    [ NaN, false ],
-    [ Infinity, true ],
-    [ [], true ],
-    [ new Date(), true ],
-    [ "", false ],
-    [ "" + "" + "", false ],
-    [ "Cocoa", true ],
-    [ undefined, false ],
-    [ null, false ],
-    [ Symbol(), true ],
-];
-
-for (var i = 0; i < 1e4; ++i) {
-    for (let [ value, result ] of data)
-        shouldBe(!test(value), result);
-}

Deleted: trunk/JSTests/stress/value-to-boolean.js (274036 => 274037)


--- trunk/JSTests/stress/value-to-boolean.js	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/JSTests/stress/value-to-boolean.js	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1,65 +0,0 @@
-//@ if $buildType == "release" then runDefault else skip end
-
-function assert(b) {
-    if (!b)
-        throw new Error("Bad assertion")
-}
-noInline(assert);
-
-let tests = [
-    [true, true],
-    [false, false],
-    ["", false],
-    ["" + "" + "", false],
-    ["foo", true],
-    ["foo" + "bar", true],
-    [{}, true],
-    [Symbol(), true],
-    [undefined, false],
-    [null, false],
-    [0, false],
-    [-0, false],
-    [+0, false],
-    [NaN, false],
-    [10, true],
-    [10.2012, true],
-    [function() { }, true],
-    [new String("foo"), true],
-    [new String(""), true],
-    [new String, true]
-];
-
-function test1(c) {
-    return !!c;
-}
-noInline(test1);
-
-function test2(c) {
-    if (c)
-        return true;
-    return false;
-}
-noInline(test2);
-
-function test3(c) {
-    if (!c)
-        return false;
-    return true;
-}
-noInline(test3);
-
-let testFunctions = [test1, test2, test3];
-
-for (let testFunction of testFunctions) {
-    for (let i = 0; i < 10000; i++) {
-        let item = tests[i % tests.length];
-        assert(testFunction(item[0]) === item[1]);
-    }
-}
-
-let masquerader = makeMasquerader();
-for (let testFunction of testFunctions) {
-    for (let i = 0; i < 10000; i++) {
-        assert(testFunction(masquerader) === false);
-    }
-}

Modified: trunk/Source/_javascript_Core/ChangeLog (274036 => 274037)


--- trunk/Source/_javascript_Core/ChangeLog	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1,3 +1,68 @@
+2021-03-06  Alexey Shvayka  <[email protected]>
+
+        BooleanConstructor should be inlined in DFG / FTL
+        https://bugs.webkit.org/show_bug.cgi?id=220322
+
+        Reviewed by Yusuke Suzuki.
+
+        `array.filter(Boolean)` is a rather popular idiom for removing falsy items from an array.
+        Also, `Boolean(X)` is sometimes used for explicit type casting.
+
+        This patch introduces ToBoolean DFG node and reorganizes compileLogicalNot(node) into
+        compileToBoolean(node, bool invert), leveraging already existing emitConvertValueToBoolean().
+
+        This approach is better than emitting LogicalNot<KnownBooleanUse>(LogicalNot(X)) as it results
+        in cleaner DFG node tree and is ~7% faster w/o FTL. Also, it enables adding a op_to_boolean
+        bytecode that will be generated for very common `!!X` patterns, reducing instruction count.
+
+        Just as LogicalNot, BooleanConstructor should handle masquerader objects, because Annex B
+        patches ToBoolean abstract op [1], preventing us from emitting simpler code.
+
+        This change advances provided microbenchmark by 110%, and is neutral for other ToBoolean cases.
+
+        [1]: https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-to-boolean
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleConstantInternalFunction):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGMayExit.cpp:
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileToBooleanString):
+        (JSC::DFG::SpeculativeJIT::compileToBooleanStringOrOther):
+        (JSC::DFG::SpeculativeJIT::compileStringZeroLength): Deleted.
+        (JSC::DFG::SpeculativeJIT::compileLogicalNotStringOrOther): Deleted.
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileToBooleanObjectOrOther):
+        (JSC::DFG::SpeculativeJIT::compileToBoolean):
+        (JSC::DFG::SpeculativeJIT::compile):
+        (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): Deleted.
+        (JSC::DFG::SpeculativeJIT::compileLogicalNot): Deleted.
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileToBooleanObjectOrOther):
+        (JSC::DFG::SpeculativeJIT::compileToBoolean):
+        (JSC::DFG::SpeculativeJIT::compile):
+        (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot): Deleted.
+        (JSC::DFG::SpeculativeJIT::compileLogicalNot): Deleted.
+        * dfg/DFGWatchpointCollectionPhase.cpp:
+        (JSC::DFG::WatchpointCollectionPhase::handle):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileToBoolean):
+
 2021-03-06  Tim Horton  <[email protected]>
 
         <model> should create a model-owning compositing layer

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1348,18 +1348,18 @@
         executeDoubleUnaryOpEffects(node, arithUnaryFunction(node->arithUnaryType()));
         break;
             
+    case ToBoolean:
     case LogicalNot: {
-        switch (booleanResult(node, forNode(node->child1()))) {
-        case TriState::True:
-            setConstant(node, jsBoolean(false));
-            break;
-        case TriState::False:
-            setConstant(node, jsBoolean(true));
-            break;
-        case TriState::Indeterminate:
+        TriState result = booleanResult(node, forNode(node->child1()));
+        if (result == TriState::Indeterminate) {
             setNonCellTypeForNode(node, SpecBoolean);
             break;
         }
+
+        bool resultAsBool = result == TriState::True;
+        if (node->op() == LogicalNot)
+            resultAsBool = !resultAsBool;
+        setConstant(node, jsBoolean(resultAsBool));
         break;
     }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -31,6 +31,7 @@
 #include "ArithProfile.h"
 #include "ArrayConstructor.h"
 #include "ArrayPrototype.h"
+#include "BooleanConstructor.h"
 #include "BuiltinNames.h"
 #include "ByValInfo.h"
 #include "BytecodeGenerator.h"
@@ -4067,6 +4068,22 @@
 
         return true;
     }
+
+    if (function->classInfo(*m_vm) == BooleanConstructor::info()) {
+        if (kind == CodeForConstruct)
+            return false;
+
+        insertChecks();
+
+        Node* resultNode;
+        if (argumentCountIncludingThis <= 1)
+            resultNode = jsConstant(jsBoolean(false));
+        else
+            resultNode = addToGraph(ToBoolean, get(virtualRegisterForArgumentIncludingThis(1, registerOffset)));
+
+        set(result, resultNode);
+        return true;
+    }
     
     if (function->classInfo(*m_vm) == StringConstructor::info()) {
         insertChecks();

Modified: trunk/Source/_javascript_Core/dfg/DFGClobberize.h (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGClobberize.h	2021-03-06 14:42:37 UTC (rev 274037)
@@ -233,6 +233,7 @@
     case NumberIsInteger:
     case IsObject:
     case IsTypedArrayView:
+    case ToBoolean:
     case LogicalNot:
     case CheckInBounds:
     case DoubleRep:

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -156,6 +156,7 @@
     case IsCellWithType:
     case IsTypedArrayView:
     case TypeOf:
+    case ToBoolean:
     case LogicalNot:
     case Jump:
     case Branch:

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -833,6 +833,7 @@
             break;
         }
             
+        case ToBoolean:
         case LogicalNot: {
             if (node->child1()->shouldSpeculateBoolean()) {
                 if (node->child1()->result() == NodeResultBoolean) {

Modified: trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -93,6 +93,7 @@
     case ExtractOSREntryLocal:
     case ExtractCatchLocal:
     case ClearCatchLocals:
+    case ToBoolean:
     case LogicalNot:
     case NotifyWrite:
     case PutStructure:

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2021-03-06 14:42:37 UTC (rev 274037)
@@ -415,6 +415,7 @@
     macro(IsConstructor, NodeResultBoolean) \
     macro(IsTypedArrayView, NodeResultBoolean) \
     macro(TypeOf, NodeResultJS) \
+    macro(ToBoolean, NodeResultBoolean) \
     macro(LogicalNot, NodeResultBoolean) \
     macro(ToPrimitive, NodeResultJS | NodeMustGenerate) \
     macro(ToPropertyKey, NodeResultJS | NodeMustGenerate) \

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1025,6 +1025,7 @@
         case DeleteByVal:
         case DeleteById:
         case MultiDeleteByOffset:
+        case ToBoolean:
         case LogicalNot:
         case CompareLess:
         case CompareLessEq:

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2021-03-06 14:42:37 UTC (rev 274037)
@@ -270,6 +270,7 @@
     case IsCellWithType:
     case IsTypedArrayView:
     case TypeOf:
+    case ToBoolean:
     case LogicalNot:
     case ToString:
     case NumberToStringWithValidRadixConstant:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -7397,7 +7397,7 @@
     unblessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
 }
 
-void SpeculativeJIT::compileStringZeroLength(Node* node)
+void SpeculativeJIT::compileToBooleanString(Node* node, bool invert)
 {
     SpeculateCellOperand str(this, node->child1());
     GPRReg strGPR = str.gpr();
@@ -7409,11 +7409,11 @@
     GPRReg eqGPR = eq.gpr();
 
     m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(vm())), eqGPR);
-    m_jit.comparePtr(CCallHelpers::Equal, strGPR, eqGPR, eqGPR);
+    m_jit.comparePtr(invert ? CCallHelpers::Equal : CCallHelpers::NotEqual, strGPR, eqGPR, eqGPR);
     unblessedBooleanResult(eqGPR, node);
 }
 
-void SpeculativeJIT::compileLogicalNotStringOrOther(Node* node)
+void SpeculativeJIT::compileToBooleanStringOrOther(Node* node, bool invert)
 {
     JSValueOperand value(this, node->child1(), ManualOperandSpeculation);
     GPRTemporary temp(this);
@@ -7426,17 +7426,16 @@
         valueRegs, node->child1(), (~SpecCellCheck) | SpecString, m_jit.branchIfNotString(cellGPR));
 
     m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), jsEmptyString(vm())), tempGPR);
-    m_jit.comparePtr(CCallHelpers::Equal, cellGPR, tempGPR, tempGPR);
+    m_jit.comparePtr(invert ? CCallHelpers::Equal : CCallHelpers::NotEqual, cellGPR, tempGPR, tempGPR);
     auto done = m_jit.jump();
 
     notCell.link(&m_jit);
     DFG_TYPE_CHECK(
         valueRegs, node->child1(), SpecCellCheck | SpecOther, m_jit.branchIfNotOther(valueRegs, tempGPR));
-    m_jit.move(TrustedImm32(1), tempGPR);
+    m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), tempGPR);
 
     done.link(&m_jit);
     unblessedBooleanResult(tempGPR, node);
-
 }
 
 void SpeculativeJIT::emitStringBranch(Edge nodeUse, BasicBlock* taken, BasicBlock* notTaken)

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1169,9 +1169,10 @@
     void compileObjectEquality(Node*);
     void compileObjectStrictEquality(Edge objectChild, Edge otherChild);
     void compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild);
-    void compileObjectOrOtherLogicalNot(Edge value);
-    void compileLogicalNot(Node*);
-    void compileLogicalNotStringOrOther(Node*);
+    void compileToBoolean(Node*, bool invert);
+    void compileToBooleanObjectOrOther(Edge value, bool invert);
+    void compileToBooleanString(Node*, bool invert);
+    void compileToBooleanStringOrOther(Node*, bool invert);
     void compileStringEquality(
         Node*, GPRReg leftGPR, GPRReg rightGPR, GPRReg lengthGPR,
         GPRReg leftTempGPR, GPRReg rightTempGPR, GPRReg leftTemp2GPR,
@@ -1181,7 +1182,6 @@
     void compileStringIdentEquality(Node*);
     void compileStringToUntypedEquality(Node*, Edge stringEdge, Edge untypedEdge);
     void compileStringIdentToNotStringVarEquality(Node*, Edge stringEdge, Edge notStringVarEdge);
-    void compileStringZeroLength(Node*);
     void compileMiscStrictEq(Node*);
 
     void compileSymbolEquality(Node*);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1458,7 +1458,7 @@
     booleanResult(resultPayloadGPR, node);
 }
 
-void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
+void SpeculativeJIT::compileToBooleanObjectOrOther(Edge nodeUse, bool invert)
 {
     JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
     GPRTemporary resultPayload(this);
@@ -1504,7 +1504,7 @@
 
         isNotMasqueradesAsUndefined.link(&m_jit);
     }
-    m_jit.move(TrustedImm32(0), resultPayloadGPR);
+    m_jit.move(invert ? TrustedImm32(0) : TrustedImm32(1), resultPayloadGPR);
     MacroAssembler::Jump done = m_jit.jump();
     
     notCell.link(&m_jit);
@@ -1519,7 +1519,7 @@
                 resultPayloadGPR, 
                 TrustedImm32(JSValue::NullTag)));
     }
-    m_jit.move(TrustedImm32(1), resultPayloadGPR);
+    m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
     
     done.link(&m_jit);
     
@@ -1526,7 +1526,7 @@
     booleanResult(resultPayloadGPR, m_currentNode);
 }
 
-void SpeculativeJIT::compileLogicalNot(Node* node)
+void SpeculativeJIT::compileToBoolean(Node* node, bool invert)
 {
     switch (node->child1().useKind()) {
     case BooleanUse:
@@ -1533,13 +1533,18 @@
     case KnownBooleanUse: {
         SpeculateBooleanOperand value(this, node->child1());
         GPRTemporary result(this, Reuse, value);
-        m_jit.xor32(TrustedImm32(1), value.gpr(), result.gpr());
+
+        if (invert)
+            m_jit.xor32(TrustedImm32(1), value.gpr(), result.gpr());
+        else
+            m_jit.move(value.gpr(), result.gpr());
+
         booleanResult(result.gpr(), node);
         return;
     }
         
     case ObjectOrOtherUse: {
-        compileObjectOrOtherLogicalNot(node->child1());
+        compileToBooleanObjectOrOther(node->child1(), invert);
         return;
     }
         
@@ -1546,7 +1551,7 @@
     case Int32Use: {
         SpeculateInt32Operand value(this, node->child1());
         GPRTemporary resultPayload(this, Reuse, value);
-        m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), resultPayload.gpr());
+        m_jit.compare32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, value.gpr(), MacroAssembler::TrustedImm32(0), resultPayload.gpr());
         booleanResult(resultPayload.gpr(), node);
         return;
     }
@@ -1555,9 +1560,9 @@
         SpeculateDoubleOperand value(this, node->child1());
         FPRTemporary scratch(this);
         GPRTemporary resultPayload(this);
-        m_jit.move(TrustedImm32(0), resultPayload.gpr());
+        m_jit.move(invert ? TrustedImm32(0) : TrustedImm32(1), resultPayload.gpr());
         MacroAssembler::Jump nonZero = m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr());
-        m_jit.move(TrustedImm32(1), resultPayload.gpr());
+        m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayload.gpr());
         nonZero.link(&m_jit);
         booleanResult(resultPayload.gpr(), node);
         return;
@@ -1574,16 +1579,17 @@
 
         bool shouldCheckMasqueradesAsUndefined = !masqueradesAsUndefinedWatchpointIsStillValid();
         JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic);
-        bool negateResult = true;
-        m_jit.emitConvertValueToBoolean(vm(), arg1.jsValueRegs(), resultGPR, temp.gpr(), valueFPR.fpr(), tempFPR.fpr(), shouldCheckMasqueradesAsUndefined, globalObject, negateResult);
+        m_jit.emitConvertValueToBoolean(vm(), arg1.jsValueRegs(), resultGPR, temp.gpr(), valueFPR.fpr(), tempFPR.fpr(), shouldCheckMasqueradesAsUndefined, globalObject, invert);
         booleanResult(resultGPR, node);
         return;
     }
     case StringUse:
-        return compileStringZeroLength(node);
+        compileToBooleanString(node, invert);
+        return;
 
     case StringOrOtherUse:
-        return compileLogicalNotStringOrOther(node);
+        compileToBooleanStringOrOther(node, invert);
+        return;
 
     default:
         RELEASE_ASSERT_NOT_REACHED();
@@ -2159,10 +2165,18 @@
         compileArithUnary(node);
         break;
 
-    case LogicalNot:
-        compileLogicalNot(node);
+    case ToBoolean: {
+        bool invert = false;
+        compileToBoolean(node, invert);
         break;
+    }
 
+    case LogicalNot: {
+        bool invert = true;
+        compileToBoolean(node, invert);
+        break;
+    }
+
     case CompareLess:
         if (compare(node, JITCompiler::LessThan, JITCompiler::DoubleLessThanAndOrdered, operationCompareLess))
             return;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1800,7 +1800,7 @@
     unblessedBooleanResult(resultGPR, node);
 }
 
-void SpeculativeJIT::compileObjectOrOtherLogicalNot(Edge nodeUse)
+void SpeculativeJIT::compileToBooleanObjectOrOther(Edge nodeUse, bool invert)
 {
     JSValueOperand value(this, nodeUse, ManualOperandSpeculation);
     GPRTemporary result(this);
@@ -1848,7 +1848,7 @@
 
         isNotMasqueradesAsUndefined.link(&m_jit);
     }
-    m_jit.move(TrustedImm32(JSValue::ValueFalse), resultGPR);
+    m_jit.move(invert ? TrustedImm32(JSValue::ValueFalse) : TrustedImm32(JSValue::ValueTrue), resultGPR);
     MacroAssembler::Jump done = m_jit.jump();
     
     notCell.link(&m_jit);
@@ -1862,7 +1862,7 @@
                 resultGPR, 
                 MacroAssembler::TrustedImm64(JSValue::ValueNull)));
     }
-    m_jit.move(TrustedImm32(JSValue::ValueTrue), resultGPR);
+    m_jit.move(invert ? TrustedImm32(JSValue::ValueTrue) : TrustedImm32(JSValue::ValueFalse), resultGPR);
     
     done.link(&m_jit);
     
@@ -1869,11 +1869,11 @@
     jsValueResult(resultGPR, m_currentNode, DataFormatJSBoolean);
 }
 
-void SpeculativeJIT::compileLogicalNot(Node* node)
+void SpeculativeJIT::compileToBoolean(Node* node, bool invert)
 {
     switch (node->child1().useKind()) {
     case ObjectOrOtherUse: {
-        compileObjectOrOtherLogicalNot(node->child1());
+        compileToBooleanObjectOrOther(node->child1(), invert);
         return;
     }
         
@@ -1880,7 +1880,7 @@
     case Int32Use: {
         SpeculateInt32Operand value(this, node->child1());
         GPRTemporary result(this, Reuse, value);
-        m_jit.compare32(MacroAssembler::Equal, value.gpr(), MacroAssembler::TrustedImm32(0), result.gpr());
+        m_jit.compare32(invert ? MacroAssembler::Equal : MacroAssembler::NotEqual, value.gpr(), MacroAssembler::TrustedImm32(0), result.gpr());
         m_jit.or32(TrustedImm32(JSValue::ValueFalse), result.gpr());
         jsValueResult(result.gpr(), node, DataFormatJSBoolean);
         return;
@@ -1890,9 +1890,9 @@
         SpeculateDoubleOperand value(this, node->child1());
         FPRTemporary scratch(this);
         GPRTemporary result(this);
-        m_jit.move(TrustedImm32(JSValue::ValueFalse), result.gpr());
+        m_jit.move(invert ? TrustedImm32(JSValue::ValueFalse) : TrustedImm32(JSValue::ValueTrue), result.gpr());
         MacroAssembler::Jump nonZero = m_jit.branchDoubleNonZero(value.fpr(), scratch.fpr());
-        m_jit.xor32(TrustedImm32(true), result.gpr());
+        m_jit.move(invert ? TrustedImm32(JSValue::ValueTrue) : TrustedImm32(JSValue::ValueFalse), result.gpr());
         nonZero.link(&m_jit);
         jsValueResult(result.gpr(), node, DataFormatJSBoolean);
         return;
@@ -1904,8 +1904,10 @@
             SpeculateBooleanOperand value(this, node->child1());
             GPRTemporary result(this, Reuse, value);
             
-            m_jit.move(value.gpr(), result.gpr());
-            m_jit.xor64(TrustedImm32(true), result.gpr());
+            if (invert)
+                m_jit.xor32(TrustedImm32(1), value.gpr(), result.gpr());
+            else
+                m_jit.move(value.gpr(), result.gpr());
             
             jsValueResult(result.gpr(), node, DataFormatJSBoolean);
             return;
@@ -1919,7 +1921,7 @@
         typeCheck(
             JSValueRegs(value.gpr()), node->child1(), SpecBoolean, m_jit.branchTest64(
                 JITCompiler::NonZero, result.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
-        m_jit.xor64(TrustedImm32(JSValue::ValueTrue), result.gpr());
+        m_jit.xor64(invert ? TrustedImm32(JSValue::ValueTrue) : TrustedImm32(JSValue::ValueFalse), result.gpr());
         
         // If we add a DataFormatBool, we should use it here.
         jsValueResult(result.gpr(), node, DataFormatJSBoolean);
@@ -1944,17 +1946,18 @@
             scratch.emplace(this);
             scratchGPR = scratch->gpr();
         }
-        bool negateResult = true;
-        m_jit.emitConvertValueToBoolean(vm(), JSValueRegs(arg1GPR), resultGPR, scratchGPR, valueFPR.fpr(), tempFPR.fpr(), shouldCheckMasqueradesAsUndefined, globalObject, negateResult);
+        m_jit.emitConvertValueToBoolean(vm(), JSValueRegs(arg1GPR), resultGPR, scratchGPR, valueFPR.fpr(), tempFPR.fpr(), shouldCheckMasqueradesAsUndefined, globalObject, invert);
         m_jit.or32(TrustedImm32(JSValue::ValueFalse), resultGPR);
         jsValueResult(resultGPR, node, DataFormatJSBoolean);
         return;
     }
     case StringUse:
-        return compileStringZeroLength(node);
+        compileToBooleanString(node, invert);
+        return;
 
     case StringOrOtherUse:
-        return compileLogicalNotStringOrOther(node);
+        compileToBooleanStringOrOther(node, invert);
+        return;
 
     default:
         DFG_CRASH(m_jit.graph(), node, "Bad use kind");
@@ -2529,10 +2532,18 @@
         compileArithUnary(node);
         break;
 
-    case LogicalNot:
-        compileLogicalNot(node);
+    case ToBoolean: {
+        bool invert = false;
+        compileToBoolean(node, invert);
         break;
+    }
 
+    case LogicalNot: {
+        bool invert = true;
+        compileToBoolean(node, invert);
+        break;
+    }
+
     case CompareLess:
         if (compare(node, JITCompiler::LessThan, JITCompiler::DoubleLessThanAndOrdered, operationCompareLess))
             return;

Modified: trunk/Source/_javascript_Core/dfg/DFGWatchpointCollectionPhase.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/dfg/DFGWatchpointCollectionPhase.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/dfg/DFGWatchpointCollectionPhase.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -83,6 +83,7 @@
                 handleMasqueradesAsUndefined();
             break;
             
+        case ToBoolean:
         case LogicalNot:
         case Branch:
             switch (m_node->child1().useKind()) {

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -195,6 +195,7 @@
     case LoadVarargs:
     case ValueToInt32:
     case Branch:
+    case ToBoolean:
     case LogicalNot:
     case AssertInBounds:
     case CheckInBounds:

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (274036 => 274037)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2021-03-06 14:31:56 UTC (rev 274036)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2021-03-06 14:42:37 UTC (rev 274037)
@@ -1320,6 +1320,9 @@
         case SameValue:
             compileSameValue();
             break;
+        case ToBoolean:
+            compileToBoolean();
+            break;
         case LogicalNot:
             compileLogicalNot();
             break;
@@ -9637,6 +9640,11 @@
         setBoolean(vmCall(Int32, operationSameValue, weakPointer(globalObject), lowJSValue(m_node->child1()), lowJSValue(m_node->child2())));
     }
     
+    void compileToBoolean()
+    {
+        setBoolean(boolify(m_node->child1()));
+    }
+
     void compileLogicalNot()
     {
         setBoolean(m_out.logicalNot(boolify(m_node->child1())));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to