DFG should really support jneq_ptr
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Jul 2016 19:12:57 +0000 (19:12 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Jul 2016 19:12:57 +0000 (19:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=159700

Reviewed by Keith Miller.

Source/JavaScriptCore:

Prior to this change, DFG statically speculated that jneq_ptr would always fall through. This
meant that programs that called o.apply() or o.call() where apply or call weren't the
expected ones (i.e. the function.prototype.apply/call) would rage-recompile forever.

This adds profiling to jneq_ptr. We now know if it always falls through or sometimes doesn't.
If it sometimes doesn't, we now emit an actual control flow diamond. I decided to add a new
NodeType for "equal pointer", since none of the existing ones really captured that. For
example, there was no way to express "equal pointer" for strings or symbols. We don't use it
for that right now, but we might, and if we did, then it would be hugely surprising that the
DFG interpreted this as value equality. So, the DFG now has CompareEqPtr, which means exactly
what jneq_ptr means by "equal pointer".

This is an enormous speed-up on microbenchmarks. I would assume that it's a speed-up on some
real things, too, but I don't know that for a fact.

* bytecode/BytecodeList.json:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitJumpIfNotFunctionCall):
(JSC::BytecodeGenerator::emitJumpIfNotFunctionApply):
(JSC::BytecodeGenerator::emitExpectedFunctionSnippet):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasCellOperand):
* dfg/DFGNodeType.h:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileRecordRegExpCachedResult):
(JSC::DFG::SpeculativeJIT::compileCompareEqPtr):
* 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::compileCompareStrictEq):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareEqPtr):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareLess):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEqConstant): Deleted.
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_jneq_ptr):
(JSC::JIT::emit_op_eq):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_jneq_ptr):
(JSC::JIT::emit_op_eq):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:

LayoutTests:

These tests now run super fast.

* js/regress/apply-not-apply-expected.txt: Added.
* js/regress/apply-not-apply.html: Added.
* js/regress/call-or-not-call-expected.txt: Added.
* js/regress/call-or-not-call.html: Added.
* js/regress/script-tests/apply-not-apply.js: Added.
(let.o.apply):
(foo):
* js/regress/script-tests/call-or-not-call.js: Added.
(let.o.call):
(foo):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@203361 268f45cc-cd09-0410-ab3c-d52691b4dbfc

31 files changed:
LayoutTests/ChangeLog
LayoutTests/js/regress/apply-not-apply-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/apply-not-apply.html [new file with mode: 0644]
LayoutTests/js/regress/call-or-not-call-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/call-or-not-call.html [new file with mode: 0644]
LayoutTests/js/regress/script-tests/apply-not-apply.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/call-or-not-call.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNode.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/dfg/DFGValidate.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

index 7a2838f..ee93d2a 100644 (file)
@@ -1,3 +1,23 @@
+2016-07-12  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG should really support jneq_ptr
+        https://bugs.webkit.org/show_bug.cgi?id=159700
+
+        Reviewed by Keith Miller.
+        
+        These tests now run super fast.
+
+        * js/regress/apply-not-apply-expected.txt: Added.
+        * js/regress/apply-not-apply.html: Added.
+        * js/regress/call-or-not-call-expected.txt: Added.
+        * js/regress/call-or-not-call.html: Added.
+        * js/regress/script-tests/apply-not-apply.js: Added.
+        (let.o.apply):
+        (foo):
+        * js/regress/script-tests/call-or-not-call.js: Added.
+        (let.o.call):
+        (foo):
+
 2016-07-18  Ryan Haddad  <ryanhaddad@apple.com>
 
         Marking fast/shapes/shape-outside-floats/shape-outside-big-box-border-radius-002.html as flaky on ios-sim
diff --git a/LayoutTests/js/regress/apply-not-apply-expected.txt b/LayoutTests/js/regress/apply-not-apply-expected.txt
new file mode 100644 (file)
index 0000000..3e8ff4d
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/apply-not-apply
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/apply-not-apply.html b/LayoutTests/js/regress/apply-not-apply.html
new file mode 100644 (file)
index 0000000..5dcb5bc
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/apply-not-apply.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/call-or-not-call-expected.txt b/LayoutTests/js/regress/call-or-not-call-expected.txt
new file mode 100644 (file)
index 0000000..2ca5040
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/call-or-not-call
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/call-or-not-call.html b/LayoutTests/js/regress/call-or-not-call.html
new file mode 100644 (file)
index 0000000..14cd988
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="../../resources/regress-pre.js"></script>
+<script src="script-tests/call-or-not-call.js"></script>
+<script src="../../resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/apply-not-apply.js b/LayoutTests/js/regress/script-tests/apply-not-apply.js
new file mode 100644 (file)
index 0000000..4d6e946
--- /dev/null
@@ -0,0 +1,26 @@
+"use strict";
+
+(function() {
+    let o = {
+        apply(a, b) {
+            return a + b;
+        }
+    };
+    
+    function foo() {
+        let result = 0;
+        for (let i = 0; i < 1000; ++i)
+            result = o.apply(result, 1);
+        return result;
+    }
+    
+    noInline(foo);
+    
+    let result = 0;
+    for (let i = 0; i < 10000; ++i)
+        result += foo();
+    
+    if (result != 10000000)
+        throw new "Bad result: " + result;
+})();
+
diff --git a/LayoutTests/js/regress/script-tests/call-or-not-call.js b/LayoutTests/js/regress/script-tests/call-or-not-call.js
new file mode 100644 (file)
index 0000000..4622885
--- /dev/null
@@ -0,0 +1,28 @@
+"use strict";
+
+(function() {
+    let o = {
+        call(ignored, a, b) {
+            return a + b;
+        }
+    };
+    
+    let a = [o, (a, b) => a - 2 * b];
+    
+    function foo() {
+        let result = 0;
+        for (let i = 0; i < 1000; ++i)
+            result = a[((i % 5) == 0) | 0].call(null, result, 1);
+        return result;
+    }
+    
+    noInline(foo);
+    
+    let result = 0;
+    for (let i = 0; i < 10000; ++i)
+        result += foo();
+    
+    if (result != 4000000)
+        throw "Bad result: " + result;
+})();
+
index dd02145..6686f58 100644 (file)
@@ -1,5 +1,75 @@
 2016-07-12  Filip Pizlo  <fpizlo@apple.com>
 
+        DFG should really support jneq_ptr
+        https://bugs.webkit.org/show_bug.cgi?id=159700
+
+        Reviewed by Keith Miller.
+        
+        Prior to this change, DFG statically speculated that jneq_ptr would always fall through. This
+        meant that programs that called o.apply() or o.call() where apply or call weren't the
+        expected ones (i.e. the function.prototype.apply/call) would rage-recompile forever.
+        
+        This adds profiling to jneq_ptr. We now know if it always falls through or sometimes doesn't.
+        If it sometimes doesn't, we now emit an actual control flow diamond. I decided to add a new
+        NodeType for "equal pointer", since none of the existing ones really captured that. For
+        example, there was no way to express "equal pointer" for strings or symbols. We don't use it
+        for that right now, but we might, and if we did, then it would be hugely surprising that the
+        DFG interpreted this as value equality. So, the DFG now has CompareEqPtr, which means exactly
+        what jneq_ptr means by "equal pointer".
+        
+        This is an enormous speed-up on microbenchmarks. I would assume that it's a speed-up on some
+        real things, too, but I don't know that for a fact.
+
+        * bytecode/BytecodeList.json:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitJumpIfNotFunctionCall):
+        (JSC::BytecodeGenerator::emitJumpIfNotFunctionApply):
+        (JSC::BytecodeGenerator::emitExpectedFunctionSnippet):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::hasCellOperand):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileRecordRegExpCachedResult):
+        (JSC::DFG::SpeculativeJIT::compileCompareEqPtr):
+        * 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::compileCompareStrictEq):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareEqPtr):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareLess):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEqConstant): Deleted.
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_jneq_ptr):
+        (JSC::JIT::emit_op_eq):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_jneq_ptr):
+        (JSC::JIT::emit_op_eq):
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+
+2016-07-12  Filip Pizlo  <fpizlo@apple.com>
+
         OSR entry into DFG has problems with lexical scoping
         https://bugs.webkit.org/show_bug.cgi?id=159687
 
index 88a7c52..5df99d9 100644 (file)
@@ -86,7 +86,7 @@
             { "name" : "op_jfalse", "length" : 3 },
             { "name" : "op_jeq_null", "length" : 3 },
             { "name" : "op_jneq_null", "length" : 3 },
-            { "name" : "op_jneq_ptr", "length" : 4 },
+            { "name" : "op_jneq_ptr", "length" : 5 },
             { "name" : "op_jless", "length" : 4 },
             { "name" : "op_jlesseq", "length" : 4 },
             { "name" : "op_jgreater", "length" : 4 },
index 13b150f..cb0d39d 100644 (file)
@@ -1311,6 +1311,7 @@ void CodeBlock::dumpBytecode(
             int offset = (++it)->u.operand;
             printLocationAndOp(out, exec, location, it, "jneq_ptr");
             out.printf("%s, %d (%p), %d(->%d)", registerName(r0).data(), pointer, m_globalObject->actualPointerFor(pointer), offset, location + offset);
+            ++it;
             break;
         }
         case op_jless: {
index 741aa3e..0fc8ceb 100644 (file)
@@ -1448,6 +1448,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(RegisterID* cond,
     instructions().append(cond->index());
     instructions().append(Special::CallFunction);
     instructions().append(target->bind(begin, instructions().size()));
+    instructions().append(0);
     return target;
 }
 
@@ -1459,6 +1460,7 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond
     instructions().append(cond->index());
     instructions().append(Special::ApplyFunction);
     instructions().append(target->bind(begin, instructions().size()));
+    instructions().append(0);
     return target;
 }
 
@@ -3059,6 +3061,7 @@ ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst,
         instructions().append(func->index());
         instructions().append(Special::ObjectConstructor);
         instructions().append(realCall->bind(begin, instructions().size()));
+        instructions().append(0);
         
         if (dst != ignoredResult())
             emitNewObject(dst);
@@ -3079,6 +3082,7 @@ ExpectedFunction BytecodeGenerator::emitExpectedFunctionSnippet(RegisterID* dst,
         instructions().append(func->index());
         instructions().append(Special::ArrayConstructor);
         instructions().append(realCall->bind(begin, instructions().size()));
+        instructions().append(0);
         
         if (dst != ignoredResult()) {
             if (callArguments.argumentCountIncludingThis() == 2)
index 0b23599..9741315 100644 (file)
@@ -1522,6 +1522,18 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
         
+    case CompareEqPtr: {
+        Node* childNode = node->child1().node();
+        JSValue childValue = forNode(childNode).value();
+        if (childValue) {
+            setConstant(node, jsBoolean(childValue.isCell() && childValue.asCell() == node->cellOperand()->cell()));
+            break;
+        }
+        
+        forNode(node).setType(SpecBoolean);
+        break;
+    }
+        
     case StringCharCodeAt:
         forNode(node).setType(SpecInt32Only);
         break;
index 8d1f1f5..433a6e7 100644 (file)
@@ -4564,17 +4564,23 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_construct_varargs);
         }
             
-        case op_jneq_ptr:
-            // Statically speculate for now. It makes sense to let speculate-only jneq_ptr
-            // support simmer for a while before making it more general, since it's
-            // already gnarly enough as it is.
-            ASSERT(pointerIsFunction(currentInstruction[2].u.specialPointer));
-            addToGraph(
-                CheckCell,
-                OpInfo(m_graph.freeze(static_cast<JSCell*>(actualPointerFor(
-                    m_inlineStackTop->m_codeBlock, currentInstruction[2].u.specialPointer)))),
-                get(VirtualRegister(currentInstruction[1].u.operand)));
+        case op_jneq_ptr: {
+            Special::Pointer specialPointer = currentInstruction[2].u.specialPointer;
+            ASSERT(pointerIsCell(specialPointer));
+            JSCell* actualPointer = static_cast<JSCell*>(
+                actualPointerFor(m_inlineStackTop->m_codeBlock, specialPointer));
+            FrozenValue* frozenPointer = m_graph.freeze(actualPointer);
+            int operand = currentInstruction[1].u.operand;
+            unsigned relativeOffset = currentInstruction[3].u.operand;
+            Node* child = get(VirtualRegister(operand));
+            if (currentInstruction[4].u.operand) {
+                Node* condition = addToGraph(CompareEqPtr, OpInfo(frozenPointer), child);
+                addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jneq_ptr), m_currentIndex + relativeOffset)), condition);
+                LAST_OPCODE(op_jneq_ptr);
+            }
+            addToGraph(CheckCell, OpInfo(frozenPointer), child);
             NEXT_OPCODE(op_jneq_ptr);
+        }
 
         case op_resolve_scope: {
             int dst = currentInstruction[1].u.operand;
index 09dbe06..dcc62be 100644 (file)
@@ -164,6 +164,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case GetGlobalObject:
     case StringCharCodeAt:
     case CompareStrictEq:
+    case CompareEqPtr:
     case IsJSArray:
     case IsEmpty:
     case IsUndefined:
index caf30e3..52f7ec4 100644 (file)
@@ -139,6 +139,7 @@ bool doesGC(Graph& graph, Node* node)
     case CompareGreaterEq:
     case CompareEq:
     case CompareStrictEq:
+    case CompareEqPtr:
     case Call:
     case TailCallInlinedCaller:
     case Construct:
index 974590a..e0122d1 100644 (file)
@@ -620,7 +620,7 @@ private:
             }
             break;
         }
-
+            
         case StringFromCharCode:
             if (node->child1()->shouldSpeculateInt32())
                 fixEdge<Int32Use>(node->child1());
@@ -1589,6 +1589,7 @@ private:
         case PutByIdWithThis:
         case PutByValWithThis:
         case GetByValWithThis:
+        case CompareEqPtr:
             break;
             
             break;
index 3bf3b2c..f2de2d0 100644 (file)
@@ -1467,6 +1467,7 @@ struct Node {
         case NewGeneratorFunction:
         case CreateActivation:
         case MaterializeCreateActivation:
+        case CompareEqPtr:
             return true;
         default:
             return false;
index f93b3bf..b293898 100644 (file)
@@ -265,6 +265,7 @@ namespace JSC { namespace DFG {
     macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate) \
     macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \
     macro(CompareStrictEq, NodeResultBoolean) \
+    macro(CompareEqPtr, NodeResultBoolean) \
     \
     /* Calls. */\
     macro(Call, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
index a2dbe44..a7c8d2a 100644 (file)
@@ -781,6 +781,7 @@ private:
         case CompareGreaterEq:
         case CompareEq:
         case CompareStrictEq:
+        case CompareEqPtr:
         case OverridesHasInstance:
         case InstanceOf:
         case InstanceOfCustom:
index c1a3bbe..0ae166f 100644 (file)
@@ -235,6 +235,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case CompareGreaterEq:
     case CompareEq:
     case CompareStrictEq:
+    case CompareEqPtr:
     case Call:
     case TailCallInlinedCaller:
     case Construct:
index 967faca..a2ba174 100644 (file)
@@ -8256,6 +8256,19 @@ void SpeculativeJIT::compileRecordRegExpCachedResult(Node* node)
     noResult(node);
 }
 
+void SpeculativeJIT::compileCompareEqPtr(Node* node)
+{
+    JSValueOperand operand(this, node->child1());
+    GPRTemporary result(this);
+    JSValueRegs regs = operand.jsValueRegs();
+    GPRReg resultGPR = result.gpr();
+    m_jit.boxBooleanPayload(false, resultGPR);
+    JITCompiler::JumpList notEqual = m_jit.branchIfNotEqual(regs, node->cellOperand()->value());
+    m_jit.boxBooleanPayload(true, resultGPR);
+    notEqual.link(&m_jit);
+    blessedBooleanResult(resultGPR, node);
+}
+
 } } // namespace JSC::DFG
 
 #endif
index 6ca60bf..bae0f77 100644 (file)
@@ -2559,6 +2559,7 @@ public:
     void compileResolveScope(Node*);
     void compileGetDynamicVar(Node*);
     void compilePutDynamicVar(Node*);
+    void compileCompareEqPtr(Node*);
 
     void moveTrueTo(GPRReg);
     void moveFalseTo(GPRReg);
index 8d336ff..d4b9dfd 100644 (file)
@@ -2387,6 +2387,10 @@ void SpeculativeJIT::compile(Node* node)
         if (compileStrictEq(node))
             return;
         break;
+        
+    case CompareEqPtr:
+        compileCompareEqPtr(node);
+        break;
 
     case StringCharCodeAt: {
         compileGetCharCodeAt(node);
index dadb1f5..b585820 100644 (file)
@@ -2522,6 +2522,10 @@ void SpeculativeJIT::compile(Node* node)
         if (compileStrictEq(node))
             return;
         break;
+        
+    case CompareEqPtr:
+        compileCompareEqPtr(node);
+        break;
 
     case StringCharCodeAt: {
         compileGetCharCodeAt(node);
index 6bf8322..5d8b9a8 100644 (file)
@@ -266,6 +266,10 @@ public:
                     VALIDATE((node), !!node->child1());
                     VALIDATE((node), !!node->child2());
                     break;
+                case CompareEqPtr:
+                    VALIDATE((node), !!node->child1());
+                    VALIDATE((node), !!node->cellOperand()->value() && node->cellOperand()->value().isCell());
+                    break;
                 case CheckStructure:
                 case StringFromCharCode:
                     VALIDATE((node), !!node->child1());
index ed784bf..84757bb 100644 (file)
@@ -244,6 +244,7 @@ inline CapabilityLevel canCompile(Node* node)
     case ResolveScope:
     case GetDynamicVar:
     case PutDynamicVar:
+    case CompareEqPtr:
         // These are OK.
         break;
 
index fc617fd..1a233d9 100644 (file)
@@ -819,6 +819,9 @@ private:
         case CompareGreaterEq:
             compileCompareGreaterEq();
             break;
+        case CompareEqPtr:
+            compileCompareEqPtr();
+            break;
         case LogicalNot:
             compileLogicalNot();
             break;
@@ -4984,14 +4987,12 @@ private:
         DFG_CRASH(m_graph, m_node, "Bad use kinds");
     }
     
-    void compileCompareStrictEqConstant()
+    void compileCompareEqPtr()
     {
-        JSValue constant = m_node->child2()->asJSValue();
-
         setBoolean(
             m_out.equal(
                 lowJSValue(m_node->child1()),
-                m_out.constInt64(JSValue::encode(constant))));
+                weakPointer(m_node->cellOperand()->cell())));
     }
     
     void compileCompareLess()
index d55778d..d99d415 100644 (file)
@@ -421,7 +421,10 @@ void JIT::emit_op_jneq_ptr(Instruction* currentInstruction)
     unsigned target = currentInstruction[3].u.operand;
     
     emitGetVirtualRegister(src, regT0);
-    addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(actualPointerFor(m_codeBlock, ptr))), target);
+    CCallHelpers::Jump equal = branchPtr(Equal, regT0, TrustedImmPtr(actualPointerFor(m_codeBlock, ptr)));
+    store32(TrustedImm32(1), &currentInstruction[4].u.operand);
+    addJump(jump(), target);
+    equal.link(this);
 }
 
 void JIT::emit_op_eq(Instruction* currentInstruction)
index 61cab86..63f78cd 100644 (file)
@@ -589,8 +589,12 @@ void JIT::emit_op_jneq_ptr(Instruction* currentInstruction)
     unsigned target = currentInstruction[3].u.operand;
 
     emitLoad(src, regT1, regT0);
-    addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)), target);
-    addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(actualPointerFor(m_codeBlock, ptr))), target);
+    CCallHelpers::Jump notCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
+    CCallHelpers::Jump equal = branchPtr(Equal, regT0, TrustedImmPtr(actualPointerFor(m_codeBlock, ptr)));
+    notCell.link(this);
+    store32(TrustedImm32(1), &currentInstruction[4].u.operand);
+    addJump(jump(), target);
+    equal.link(this);
 }
 
 void JIT::emit_op_eq(Instruction* currentInstruction)
index 7287f6b..803de4c 100644 (file)
@@ -1808,9 +1808,10 @@ _llint_op_jneq_ptr:
     loadp JSGlobalObject::m_specialPointers[t2, t1, 4], t1
     bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough
 .opJneqPtrBranch:
+    storei 1, 16[PC]
     dispatchBranch(12[PC])
 .opJneqPtrFallThrough:
-    dispatch(4)
+    dispatch(5)
 
 
 macro compare(integerCompare, doubleCompare, slowPath)
index b30afa2..79bb4e3 100644 (file)
@@ -1767,9 +1767,10 @@ _llint_op_jneq_ptr:
     loadp CodeBlock::m_globalObject[t2], t2
     loadp JSGlobalObject::m_specialPointers[t2, t1, 8], t1
     bpneq t1, [cfr, t0, 8], .opJneqPtrTarget
-    dispatch(4)
+    dispatch(5)
 
 .opJneqPtrTarget:
+    storei 1, 32[PB, PC, 8]
     dispatchIntIndirect(3)