Re-introduce op_bitnot
authorticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Nov 2018 02:26:59 +0000 (02:26 +0000)
committerticaiolima@gmail.com <ticaiolima@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Nov 2018 02:26:59 +0000 (02:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=190923

Reviewed by Yusuke Suzuki.

JSTests:

* stress/bit-not-must-generate.js: Added.
* stress/bitwise-not-no-int32.js: Added.

Source/JavaScriptCore:

With the introduction of BigInt as a new type, we can't emit bitwise
not as `x ^ -1` anymore, because this is incompatible with the new type.
Based on that, this Patch is adding `op_bitnot` as a new operation
into LLInt, as well as introducing ArithBitNot node into DFG to support
JIT compilation of such opcode. We will use the ValueProfile of this
intruction in the future to generate better code when its operand
is not Int32.

* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::not32):
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::not32):
* assembler/MacroAssemblerMIPS.h:
(JSC::MacroAssemblerMIPS::not32):
* bytecode/BytecodeList.rb:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finishCreation):
* bytecode/Opcode.h:
(JSC::padOpcodeName):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitUnaryOp):
* bytecompiler/NodesCodegen.cpp:
(JSC::UnaryPlusNode::emitBytecode):
(JSC::BitwiseNotNode::emitBytecode): Deleted.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileBitwiseNot):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileArithBitNot):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_op_bitnot):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* offlineasm/cloop.rb:
* parser/NodeConstructors.h:
(JSC::BitwiseNotNode::BitwiseNotNode):
* parser/Nodes.h:
* parser/ResultType.h:
(JSC::ResultType::bigIntOrInt32Type):
(JSC::ResultType::forBitOp):
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:

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

42 files changed:
JSTests/ChangeLog
JSTests/stress/bit-not-must-generate.js [new file with mode: 0644]
JSTests/stress/bitwise-not-no-int32.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
Source/JavaScriptCore/bytecode/BytecodeList.rb
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/Opcode.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/dfg/DFGOperations.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/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITArithmetic.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/offlineasm/cloop.rb
Source/JavaScriptCore/parser/NodeConstructors.h
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/parser/ResultType.h
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h

index 353d9cf..86e2a20 100644 (file)
@@ -1,3 +1,13 @@
+2018-11-26  Caio Lima  <ticaiolima@gmail.com>
+
+        Re-introduce op_bitnot
+        https://bugs.webkit.org/show_bug.cgi?id=190923
+
+        Reviewed by Yusuke Suzuki.
+
+        * stress/bit-not-must-generate.js: Added.
+        * stress/bitwise-not-no-int32.js: Added.
+
 2018-11-26  Saam barati  <sbarati@apple.com>
 
         InPlaceAbstractState::endBasicBlock rule for SetLocal should filter the value based on the flush format
diff --git a/JSTests/stress/bit-not-must-generate.js b/JSTests/stress/bit-not-must-generate.js
new file mode 100644 (file)
index 0000000..83fa63b
--- /dev/null
@@ -0,0 +1,26 @@
+function assert(a, e) {
+    if (a !== e) {
+        throw new Error("Bad!");
+    }
+}
+
+function foo(a) {
+    let loc = ~a;
+    return a + 2;
+}
+noInline(foo);
+
+let b = 0;
+let o = {
+    valueOf: function () {
+        b++;
+        return 2;
+    }
+};
+
+for (let i = 0; i < 100000; i++) {
+    assert(foo(o), 4);
+}
+
+assert(b, 200000)
+
diff --git a/JSTests/stress/bitwise-not-no-int32.js b/JSTests/stress/bitwise-not-no-int32.js
new file mode 100644 (file)
index 0000000..3a29813
--- /dev/null
@@ -0,0 +1,30 @@
+function assert(a, e, m) {
+    if (a !== e)
+        throw new Error("Expected to be: " + e + " but got: " + a);
+}
+
+function bitNot(a) {
+    return ~a;
+}
+noInline(bitNot);
+
+for (let i = 0; i < 10000; i++) {
+    let r = bitNot("0");
+    assert(r, -1);
+    r = bitNot("1");
+    assert(r, -2);
+    r = bitNot("-1");
+    assert(r, 0);
+    r = bitNot("-2");
+    assert(r, 1);
+
+    r = bitNot({ valueOf: () => 0 });
+    assert(r, -1);
+    r = bitNot({ valueOf: () => 1 });
+    assert(r, -2);
+    r = bitNot({ valueOf: () => -1 });
+    assert(r, 0);
+    r = bitNot({ valueOf: () => -2 });
+    assert(r, 1);
+}
+
index 401caff..96b0a7d 100644 (file)
@@ -1,3 +1,88 @@
+2018-11-26  Caio Lima  <ticaiolima@gmail.com>
+
+        Re-introduce op_bitnot
+        https://bugs.webkit.org/show_bug.cgi?id=190923
+
+        Reviewed by Yusuke Suzuki.
+
+        With the introduction of BigInt as a new type, we can't emit bitwise
+        not as `x ^ -1` anymore, because this is incompatible with the new type.
+        Based on that, this Patch is adding `op_bitnot` as a new operation
+        into LLInt, as well as introducing ArithBitNot node into DFG to support
+        JIT compilation of such opcode. We will use the ValueProfile of this
+        intruction in the future to generate better code when its operand
+        is not Int32.
+
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::not32):
+        * assembler/MacroAssemblerARMv7.h:
+        (JSC::MacroAssemblerARMv7::not32):
+        * assembler/MacroAssemblerMIPS.h:
+        (JSC::MacroAssemblerMIPS::not32):
+        * bytecode/BytecodeList.rb:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::finishCreation):
+        * bytecode/Opcode.h:
+        (JSC::padOpcodeName):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitUnaryOp):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::UnaryPlusNode::emitBytecode):
+        (JSC::BitwiseNotNode::emitBytecode): Deleted.
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGBackwardsPropagationPhase.cpp:
+        (JSC::DFG::BackwardsPropagationPhase::propagate):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileBitwiseNot):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithBitNot):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        * jit/JIT.h:
+        * jit/JITArithmetic.cpp:
+        (JSC::JIT::emit_op_bitnot):
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * offlineasm/cloop.rb:
+        * parser/NodeConstructors.h:
+        (JSC::BitwiseNotNode::BitwiseNotNode):
+        * parser/Nodes.h:
+        * parser/ResultType.h:
+        (JSC::ResultType::bigIntOrInt32Type):
+        (JSC::ResultType::forBitOp):
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+
 2018-11-26  Saam barati  <sbarati@apple.com>
 
         InPlaceAbstractState::endBasicBlock rule for SetLocal should filter the value based on the flush format
index d0f26d1..d91921a 100644 (file)
@@ -1045,6 +1045,11 @@ public:
         xor64(dataTempRegister, dest);
     }
 
+    void not32(RegisterID srcDest)
+    {
+        m_assembler.mvn<32>(srcDest, srcDest);
+    }
+
     void not32(RegisterID src, RegisterID dest)
     {
         m_assembler.mvn<32>(dest, src);
index e603526..197496a 100644 (file)
@@ -578,6 +578,10 @@ public:
             xor32(imm, dest, dest);
     }
     
+    void not32(RegisterID srcDest)
+    {
+        m_assembler.mvn(srcDest, srcDest);
+    }
 
     // Memory access operations:
     //
index f7db1e3..92d03c8 100644 (file)
@@ -818,6 +818,11 @@ public:
         m_assembler.xorInsn(dest, src, immTempRegister);
     }
 
+    void not32(RegisterID srcDest)
+    {
+        m_assembler.nor(srcDest, srcDest, MIPSRegisters::zero);
+    }
+
     void sqrtDouble(FPRegisterID src, FPRegisterID dst)
     {
         m_assembler.sqrtd(dst, src);
index f6e7028..773ddab 100644 (file)
@@ -269,6 +269,15 @@ op_group :ValueProfiledBinaryOp,
         profile: ValueProfile
     }
 
+op :bitnot,
+    args: {
+        dst: VirtualRegister,
+        operand: VirtualRegister,
+    },
+    metadata: {
+        profile: ValueProfile
+    }
+
 op_group :UnaryOp,
     [
         :eq_null,
index 657f3e7..2279227 100644 (file)
@@ -178,6 +178,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins
     USES(OpToString, operand)
     USES(OpToObject, operand)
     USES(OpNegate, operand)
+    USES(OpBitnot, operand)
     USES(OpEqNull, operand)
     USES(OpNeqNull, operand)
     USES(OpNot, operand)
@@ -426,6 +427,7 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins
     DEFS(OpBitand, dst)
     DEFS(OpBitxor, dst)
     DEFS(OpBitor, dst)
+    DEFS(OpBitnot, dst)
     DEFS(OpInc, srcDst)
     DEFS(OpDec, srcDst)
     DEFS(OpEq, dst)
index d4ea5dd..d34652b 100644 (file)
@@ -566,6 +566,7 @@ bool CodeBlock::finishCreation(VM& vm, ScriptExecutable* ownerExecutable, Unlink
         LINK(OpToThis, profile)
         LINK(OpBitand, profile)
         LINK(OpBitor, profile)
+        LINK(OpBitnot, profile)
 
         LINK(OpGetById, profile, hitCountForLLIntCaching)
 
index 1783c3c..298f28f 100644 (file)
@@ -109,6 +109,7 @@ IGNORE_WARNINGS_END
     macro(OpGetFromScope) \
     macro(OpBitand) \
     macro(OpBitor) \
+    macro(OpBitnot) \
 
 #define FOR_EACH_OPCODE_WITH_ARRAY_PROFILE(macro) \
     macro(OpHasIndexedProperty) \
index 9b17d89..828aed0 100644 (file)
@@ -1608,6 +1608,9 @@ RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, R
     case op_negate:
         OpNegate::emit(this, dst, src, types);
         break;
+    case op_bitnot:
+        emitUnaryOp<OpBitnot>(dst, src);
+        break;
     case op_to_number:
         emitUnaryOp<OpToNumber>(dst, src);
         break;
index d0577cc..23a14b9 100644 (file)
@@ -1889,15 +1889,6 @@ RegisterID* UnaryPlusNode::emitBytecode(BytecodeGenerator& generator, RegisterID
     generator.emitExpressionInfo(position(), position(), position());
     return generator.emitToNumber(generator.finalDestination(dst), src.get());
 }
-
-// ------------------------------ BitwiseNotNode -----------------------------------
-RegisterID* BitwiseNotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
-{
-    RefPtr<RegisterID> src2 = generator.emitLoad(nullptr, jsNumber(-1));
-    RefPtr<RegisterID> src1 = generator.emitNode(m_expr);
-    return generator.emitBinaryOp<OpBitxor>(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr->resultDescriptor(), ResultType::numberTypeIsInt32()));
-}
  
 // ------------------------------ LogicalNotNode -----------------------------------
 
index 2fa280f..703d939 100644 (file)
@@ -375,6 +375,24 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         break;
     }
             
+    case ArithBitNot: {
+        if (node->child1().useKind() == UntypedUse) {
+            clobberWorld();
+            setNonCellTypeForNode(node, SpecInt32Only);
+            break;
+        }
+
+        JSValue operand = forNode(node->child1()).value();
+        if (operand && operand.isInt32()) {
+            int32_t a = operand.asInt32();
+            setConstant(node, JSValue(~a));
+            break;
+        }
+
+        setNonCellTypeForNode(node, SpecInt32Only);
+        break;
+    }
+
     case ValueBitOr:
     case ValueBitAnd:
         clobberWorld();
index 31a342e..abaa763 100644 (file)
@@ -207,6 +207,14 @@ private:
         case CheckVarargs:
             break;
             
+        case ArithBitNot: {
+            flags |= NodeBytecodeUsesAsInt;
+            flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther);
+            flags &= ~NodeBytecodeUsesAsArrayIndex;
+            node->child1()->mergeFlags(flags);
+            break;
+        }
+
         case ArithBitAnd:
         case ArithBitOr:
         case BitXor:
index dca4d58..00deb58 100644 (file)
@@ -4892,6 +4892,13 @@ void ByteCodeParser::parseBlock(unsigned limit)
             
         // === Bitwise operations ===
 
+        case op_bitnot: {
+            auto bytecode = currentInstruction->as<OpBitnot>();
+            Node* op1 = get(bytecode.operand);
+            set(bytecode.dst, addToGraph(ArithBitNot, op1));
+            NEXT_OPCODE(op_bitnot);
+        }
+
         case op_bitand: {
             auto bytecode = currentInstruction->as<OpBitand>();
             Node* op1 = get(bytecode.lhs);
index f516ff1..c3de14b 100644 (file)
@@ -116,6 +116,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, const I
     case op_argument_count:
     case op_check_tdz:
     case op_create_this:
+    case op_bitnot:
     case op_bitand:
     case op_bitor:
     case op_bitxor:
index 4557d43..1177513 100644 (file)
@@ -262,6 +262,15 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         def(PureValue(node, node->queriedType()));
         return;
 
+    case ArithBitNot:
+        if (node->child1().useKind() == UntypedUse) {
+            read(World);
+            write(Heap);
+            return;
+        }
+        def(PureValue(node));
+        return;
+
     case ArithBitAnd:
     case ArithBitOr:
     case BitXor:
index e9a72c8..1addd5d 100644 (file)
@@ -67,6 +67,7 @@ bool doesGC(Graph& graph, Node* node)
     case Flush:
     case PhantomLocal:
     case SetArgument:
+    case ArithBitNot:
     case ArithBitAnd:
     case ArithBitOr:
     case BitXor:
index 937b2a1..aec4a21 100644 (file)
@@ -143,6 +143,17 @@ private:
             break;
         }
     
+        case ArithBitNot: {
+            if (node->child1().node()->shouldSpeculateUntypedForBitOps()) {
+                fixEdge<UntypedUse>(node->child1());
+                break;
+            }
+
+            fixIntConvertingEdge(node->child1());
+            node->clearFlags(NodeMustGenerate);
+            break;
+        }
+
         case ArithBitOr:
         case ArithBitAnd: {
             if (Node::shouldSpeculateUntypedForBitOps(node->child1().node(), node->child2().node())) {
index 954b1a1..793489d 100644 (file)
@@ -111,6 +111,7 @@ namespace JSC { namespace DFG {
     macro(InvalidationPoint, NodeMustGenerate) \
     \
     /* Nodes for bitwise operations. */\
+    macro(ArithBitNot, NodeResultInt32 | NodeMustGenerate) \
     macro(ValueBitAnd, NodeResultJS | NodeMustGenerate) \
     macro(ArithBitAnd, NodeResultInt32) \
     macro(ValueBitOr, NodeResultJS | NodeMustGenerate) \
index 7f37252..c09c160 100644 (file)
@@ -333,6 +333,20 @@ JSCell* JIT_OPERATION operationToObject(ExecState* exec, JSGlobalObject* globalO
     RELEASE_AND_RETURN(scope, value.toObject(exec, globalObject));
 }
 
+EncodedJSValue JIT_OPERATION operationValueBitNot(ExecState* exec, EncodedJSValue encodedOp1)
+{
+    VM* vm = &exec->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(*vm);
+
+    JSValue op1 = JSValue::decode(encodedOp1);
+
+    int32_t operandValue = op1.toInt32(exec);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    return JSValue::encode(jsNumber(~operandValue));
+}
+
 EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
 {
     VM* vm = &exec->vm();
index 3498791..ca83a70 100644 (file)
@@ -48,6 +48,7 @@ JSCell* JIT_OPERATION operationObjectCreateObject(ExecState*, JSObject*) WTF_INT
 JSCell* JIT_OPERATION operationCreateThis(ExecState*, JSObject* constructor, uint32_t inlineCapacity) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationToThis(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationValueBitNot(ExecState*, EncodedJSValue encodedOp1) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueBitOr(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueBitXor(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
index fe89b98..25867f8 100644 (file)
@@ -737,6 +737,7 @@ private:
             break;
         }
 
+        case ArithBitNot:
         case ArithBitAnd:
         case ArithBitOr:
         case BitXor:
index bcd09e5..6c6eada 100644 (file)
@@ -197,6 +197,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno
     case Flush:
     case PhantomLocal:
     case SetArgument:
+    case ArithBitNot:
     case ArithBitAnd:
     case ArithBitOr:
     case BitXor:
index bb37875..ddc99c3 100644 (file)
@@ -3510,6 +3510,35 @@ void SpeculativeJIT::compileInstanceOf(Node* node)
     return;
 }
 
+void SpeculativeJIT::compileBitwiseNot(Node* node)
+{
+    Edge& child1 = node->child1();
+
+    if (child1.useKind() == UntypedUse) {
+        JSValueOperand operand(this, child1);
+        JSValueRegs operandRegs = operand.jsValueRegs();
+
+        flushRegisters();
+        JSValueRegsFlushedCallResult result(this);
+        JSValueRegs resultRegs = result.regs();
+        callOperation(operationValueBitNot, resultRegs, operandRegs);
+        m_jit.exceptionCheck();
+
+        jsValueResult(resultRegs, node);
+        return;
+    }
+
+    SpeculateInt32Operand operand(this, child1);
+    GPRTemporary result(this);
+    GPRReg resultGPR = result.gpr();
+
+    m_jit.move(operand.gpr(), resultGPR);
+
+    m_jit.not32(resultGPR);
+
+    int32Result(resultGPR, node);
+}
+
 template<typename SnippetGenerator, J_JITOperation_EJJ snippetSlowPathFunction>
 void SpeculativeJIT::emitUntypedBitOp(Node* node)
 {
index d5e47c1..de0b4f3 100644 (file)
@@ -1329,6 +1329,8 @@ public:
     void compileUInt32ToNumber(Node*);
     void compileDoubleAsInt32(Node*);
 
+    void compileBitwiseNot(Node*);
+
     template<typename SnippetGenerator, J_JITOperation_EJJ slowPathFunction>
     void emitUntypedBitOp(Node*);
     void compileBitwiseOp(Node*);
index f0f620d..fb302f2 100644 (file)
@@ -1990,6 +1990,10 @@ void SpeculativeJIT::compile(Node* node)
         compileBitwiseOp(node);
         break;
 
+    case ArithBitNot:
+        compileBitwiseNot(node);
+        break;
+
     case BitRShift:
     case BitLShift:
     case BitURShift:
index de9728e..1bf72ef 100644 (file)
@@ -2074,6 +2074,10 @@ void SpeculativeJIT::compile(Node* node)
         recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat()));
         break;
 
+    case ArithBitNot:
+        compileBitwiseNot(node);
+        break;
+
     case ValueBitAnd:
     case ValueBitOr:
         compileValueBitwiseOp(node);
index 174e59a..804a3b3 100644 (file)
@@ -58,6 +58,7 @@ inline CapabilityLevel canCompile(Node* node)
     case PhantomLocal:
     case SetArgument:
     case Return:
+    case ArithBitNot:
     case ArithBitAnd:
     case ArithBitOr:
     case BitXor:
index 027a2dc..a234b32 100644 (file)
@@ -653,6 +653,9 @@ private:
         case ArithUnary:
             compileArithUnary();
             break;
+        case ArithBitNot:
+            compileArithBitNot();
+            break;
         case ValueBitAnd:
             compileValueBitAnd();
             break;
@@ -2845,6 +2848,18 @@ private:
         }
     }
     
+    void compileArithBitNot()
+    {
+        if (m_node->child1().useKind() == UntypedUse) {
+            LValue operand = lowJSValue(m_node->child1());
+            LValue result = vmCall(pointerType(), m_out.operation(operationValueBitNot), m_callFrame, operand);
+            setJSValue(result);
+            return;
+        }
+
+        setInt32(m_out.bitNot(lowInt32(m_node->child1())));
+    }
+
     void compileValueBitAnd()
     {
         if (m_node->isBinaryUseKind(BigIntUse)) {
index 21c9d29..4263d28 100644 (file)
@@ -304,6 +304,7 @@ void JIT::privateCompileMainPass()
         DEFINE_SLOW_OP(pow)
 
         DEFINE_OP(op_add)
+        DEFINE_OP(op_bitnot)
         DEFINE_OP(op_bitand)
         DEFINE_OP(op_bitor)
         DEFINE_OP(op_bitxor)
@@ -541,6 +542,7 @@ void JIT::privateCompileSlowCases()
         DEFINE_SLOWCASE_SLOW_OP(unsigned)
         DEFINE_SLOWCASE_SLOW_OP(inc)
         DEFINE_SLOWCASE_SLOW_OP(dec)
+        DEFINE_SLOWCASE_SLOW_OP(bitnot)
         DEFINE_SLOWCASE_SLOW_OP(bitand)
         DEFINE_SLOWCASE_SLOW_OP(bitor)
         DEFINE_SLOWCASE_SLOW_OP(bitxor)
index 395f538..fc710b0 100644 (file)
@@ -505,6 +505,7 @@ namespace JSC {
         void emit_op_bitand(const Instruction*);
         void emit_op_bitor(const Instruction*);
         void emit_op_bitxor(const Instruction*);
+        void emit_op_bitnot(const Instruction*);
         void emit_op_call(const Instruction*);
         void emit_op_tail_call(const Instruction*);
         void emit_op_call_eval(const Instruction*);
index 227485a..0bdc153 100644 (file)
@@ -513,6 +513,31 @@ void JIT::emitBitBinaryOpFastPath(const Instruction* currentInstruction, Profili
     addSlowCase(gen.slowPathJumpList());
 }
 
+void JIT::emit_op_bitnot(const Instruction* currentInstruction)
+{
+    auto bytecode = currentInstruction->as<OpBitnot>();
+    int result = bytecode.dst.offset();
+    int op1 = bytecode.operand.offset();
+
+#if USE(JSVALUE64)
+    JSValueRegs leftRegs = JSValueRegs(regT0);
+#else
+    JSValueRegs leftRegs = JSValueRegs(regT1, regT0);
+#endif
+
+    emitGetVirtualRegister(op1, leftRegs);
+
+    addSlowCase(branchIfNotInt32(leftRegs));
+    not32(leftRegs.payloadGPR());
+#if USE(JSVALUE64)
+    boxInt32(leftRegs.payloadGPR(), leftRegs);
+#endif
+
+    emitValueProfilingSiteIfProfiledOpcode(bytecode);
+
+    emitPutVirtualRegister(result, leftRegs);
+}
+
 void JIT::emit_op_bitand(const Instruction* currentInstruction)
 {
     emitBitBinaryOpFastPath<OpBitand, JITBitAndGenerator>(currentInstruction, ProfilingPolicy::ShouldEmitProfiling);
index 7102038..6b29219 100644 (file)
@@ -1164,8 +1164,19 @@ bitOpProfiled(bitand, OpBitand,
     macro (left, right) andi left, right end)
 
 bitOpProfiled(bitor, OpBitor,
-        macro (left, right) ori left, right end)
+    macro (left, right) ori left, right end)
 
+llintOpWithProfile(op_bitnot, OpBitnot, macro (size, get, dispatch, return)
+    get(operand, t0)
+    loadConstantOrVariable(size, t0, t2, t3)
+    bineq t2, Int32Tag, .opBitNotSlow
+    noti t3
+    return (Int32Tag, t3)
+
+ .opBitNotSlow:
+    callSlowPath(_slow_path_bitnot)
+    dispatch()
+end)
 
 llintOp(op_overrides_has_instance, OpOverridesHasInstance, macro (size, get, dispatch)
     get(dst, t3)
index 4a54d28..721a778 100644 (file)
@@ -1111,18 +1111,26 @@ bitOp(rshift, OpRshift,
 bitOp(urshift, OpUrshift,
     macro (left, right) urshifti left, right end)
 
-
-bitOp(bitxor, OpBitxor,
-    macro (left, right) xori left, right end)
-
-
 bitOpProfiled(bitand, OpBitand,
     macro (left, right) andi left, right end)
 
-
 bitOpProfiled(bitor, OpBitor,
     macro (left, right) ori left, right end)
 
+bitOp(bitxor, OpBitxor,
+    macro (left, right) xori left, right end)
+
+llintOpWithProfile(op_bitnot, OpBitnot, macro (size, get, dispatch, return)
+    get(operand, t0)
+    loadConstantOrVariableInt32(size, t0, t3, .opBitNotSlow)
+    noti t3
+    orq tagTypeNumber, t3
+    return(t3)
+.opBitNotSlow:
+    callSlowPath(_slow_path_bitnot)
+    dispatch()
+end)
+
 
 llintOp(op_overrides_has_instance, OpOverridesHasInstance, macro (size, get, dispatch)
     get(dst, t3)
index 80b82fd..144ef5d 100644 (file)
@@ -594,7 +594,7 @@ class Instruction
             cloopEmitUnaryOperation(operands, :int, "-")
 
         when "noti"
-            cloopEmitUnaryOperation(operands, :int32, "!")
+            cloopEmitUnaryOperation(operands, :int32, "~")
 
         when "loadi"
             $asm.putc "#{operands[1].clValue(:uint)} = #{operands[0].uint32MemRef};"
index a56fbd7..a2b8c5f 100644 (file)
@@ -513,8 +513,7 @@ namespace JSC {
     }
 
     inline BitwiseNotNode::BitwiseNotNode(const JSTokenLocation& location, ExpressionNode* expr)
-        : ExpressionNode(location, ResultType::forBitOp())
-        , m_expr(expr)
+        : UnaryOpNode(location, ResultType::forBitOp(), expr, op_bitnot)
     {
     }
 
index 6c27641..45e7fb1 100644 (file)
@@ -1099,18 +1099,9 @@ namespace JSC {
         NegateNode(const JSTokenLocation&, ExpressionNode*);
     };
 
-    class BitwiseNotNode final : public ExpressionNode {
+    class BitwiseNotNode final : public UnaryOpNode {
     public:
         BitwiseNotNode(const JSTokenLocation&, ExpressionNode*);
-
-    protected:
-        ExpressionNode* expr() { return m_expr; }
-        const ExpressionNode* expr() const { return m_expr; }
-
-    private:
-        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
-
-        ExpressionNode* m_expr;
     };
  
     class LogicalNotNode final : public UnaryOpNode {
index c92621a..f754d4c 100644 (file)
@@ -136,6 +136,11 @@ namespace JSC {
             return ResultType(TypeMaybeBigInt);
         }
         
+        static constexpr ResultType bigIntOrInt32Type()
+        {
+            return ResultType(TypeMaybeBigInt | TypeInt32);
+        }
+
         static constexpr ResultType unknownType()
         {
             return ResultType(TypeBits);
@@ -169,7 +174,7 @@ namespace JSC {
 
         static constexpr ResultType forBitOp()
         {
-            return numberTypeIsInt32();
+            return bigIntOrInt32Type();
         }
 
         constexpr Type bits() const { return m_bits; }
index 7787256..2bbba02 100644 (file)
@@ -690,6 +690,15 @@ SLOW_PATH_DECL(slow_path_unsigned)
     RETURN(jsNumber(a));
 }
 
+SLOW_PATH_DECL(slow_path_bitnot)
+{
+    BEGIN();
+    auto bytecode = pc->as<OpBitnot>();
+    int32_t operand = GET_C(bytecode.operand).jsValue().toInt32(exec);
+    CHECK_EXCEPTION();
+    RETURN_PROFILED(jsNumber(~operand));
+}
+
 SLOW_PATH_DECL(slow_path_bitand)
 {
     BEGIN();
index 5cfbf69..ef4ff11 100644 (file)
@@ -324,6 +324,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_lshift);
 SLOW_PATH_HIDDEN_DECL(slow_path_rshift);
 SLOW_PATH_HIDDEN_DECL(slow_path_urshift);
 SLOW_PATH_HIDDEN_DECL(slow_path_unsigned);
+SLOW_PATH_HIDDEN_DECL(slow_path_bitnot);
 SLOW_PATH_HIDDEN_DECL(slow_path_bitand);
 SLOW_PATH_HIDDEN_DECL(slow_path_bitor);
 SLOW_PATH_HIDDEN_DECL(slow_path_bitxor);