WebKit Bugzilla
Attachment 358064 Details for
Bug 182216
: [ESNext][BigInt] Implement "~" unary operation
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-182216-20181225132628.patch (text/plain), 32.12 KB, created by
Caio Lima
on 2018-12-25 08:26:31 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2018-12-25 08:26:31 PST
Size:
32.12 KB
patch
obsolete
>Subversion Revision: 239547 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 0db65496050440b7997f8f561f98171a548c011f..22a9173c775134f6a160a7e03bde1f412f78deab 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,57 @@ >+2018-12-25 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement "~" unary operation >+ https://bugs.webkit.org/show_bug.cgi?id=182216 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This Patch is adding support of BigInt into op_bitnot operations. In >+ addition, we are changing ArithBitNot to handle only Number operands, >+ while introducing a new node named ValueBitNot to handle Untyped and >+ BigInt. This node follows the same approach we are doing into other >+ arithimetic operations into DFG. >+ >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGBackwardsPropagationPhase.cpp: >+ (JSC::DFG::BackwardsPropagationPhase::propagate): >+ * 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::hasInt32Result): >+ (JSC::DFG::Node::hasNumberOrAnyIntResult): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileValueBitNot): >+ (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::compileValueBitNot): >+ (JSC::FTL::DFG::LowerDFGToB3::compileArithBitNot): >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::SLOW_PATH_DECL): >+ * runtime/JSBigInt.cpp: >+ (JSC::JSBigInt::bitwiseNot): >+ * runtime/JSBigInt.h: >+ > 2018-12-13 Yusuke Suzuki <yusukesuzuki@slowstart.org> > > [BigInt] Support BigInt in JSON.stringify >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 5197133ead4b2d28d1fb3ecfc547ff77f01ba905..b8044423d3119501b36065f4c3fe79918127b33a 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -376,13 +376,26 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >- case ArithBitNot: { >- if (node->child1().useKind() == UntypedUse) { >- clobberWorld(); >- setNonCellTypeForNode(node, SpecInt32Only); >+ case ValueBitNot: { >+ JSValue operand = forNode(node->child1()).value(); >+ if (operand && operand.isInt32()) { >+ int32_t a = operand.asInt32(); >+ didFoldClobberWorld(); >+ setConstant(node, JSValue(~a)); > break; > } > >+ if (node->child1().useKind() == BigIntUse) >+ setTypeForNode(node, SpecBigInt); >+ else { >+ clobberWorld(); >+ setTypeForNode(node, SpecBoolInt32 | SpecBigInt); >+ } >+ >+ break; >+ } >+ >+ case ArithBitNot: {; > JSValue operand = forNode(node->child1()).value(); > if (operand && operand.isInt32()) { > int32_t a = operand.asInt32(); >diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >index 05c86ed1eb05f129ed4d00206d31e4e1f25d6159..f7a69f38f5f299145a3b4f628d36d857d149118f 100644 >--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >@@ -207,6 +207,7 @@ private: > case CheckVarargs: > break; > >+ case ValueBitNot: > case ArithBitNot: { > flags |= NodeBytecodeUsesAsInt; > flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther); >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index d6e3843a8d8349490154e08777274f08655f650b..30212080544b3948f77ca8ebb9f7e2d2bf59299d 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -4926,7 +4926,10 @@ void ByteCodeParser::parseBlock(unsigned limit) > case op_bitnot: { > auto bytecode = currentInstruction->as<OpBitnot>(); > Node* op1 = get(bytecode.operand); >- set(bytecode.dst, addToGraph(ArithBitNot, op1)); >+ if (op1->hasNumberOrAnyIntResult()) >+ set(bytecode.dst, addToGraph(ArithBitNot, op1)); >+ else >+ set(bytecode.dst, addToGraph(ValueBitNot, op1)); > NEXT_OPCODE(op_bitnot); > } > >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index 48c846bd3897d14de4e25b27d9570d82da871ae9..c1034841d81ac4fcafe5ea30e02b9bfd7861197c 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -262,6 +262,15 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > def(PureValue(node, node->queriedType())); > return; > >+ case ValueBitNot: >+ if (node->child1().useKind() == BigIntUse) { >+ def(PureValue(node)); >+ return; >+ } >+ read(World); >+ write(Heap); >+ return; >+ > case ArithBitNot: > if (node->child1().useKind() == UntypedUse) { > read(World); >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index df74930bdbb3864ad944bc4720712fe0f3947bd5..be597084f9d718749abbcf059c21027d9629df98 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -100,6 +100,7 @@ bool doesGC(Graph& graph, Node* node) > case ValueBitAnd: > case ValueBitOr: > case ValueBitXor: >+ case ValueBitNot: > case ValueAdd: > case ValueSub: > case ValueMul: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index 307632dad59da8e23250db1b4497d0341ba95292..f4374a8e42e7af2735c6f9c790d9307b8a8b1fe3 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -211,14 +211,26 @@ private: > break; > } > >- case ArithBitNot: { >- if (node->child1().node()->shouldSpeculateUntypedForBitOps()) { >- fixEdge<UntypedUse>(node->child1()); >- break; >+ case ValueBitNot: { >+ Edge& operandEdge = node->child1(); >+ >+ if (operandEdge.node()->shouldSpeculateBigInt()) >+ fixEdge<BigIntUse>(operandEdge); >+ else if (operandEdge.node()->shouldSpeculateUntypedForBitOps()) >+ fixEdge<UntypedUse>(operandEdge); >+ else { >+ node->setOp(ArithBitNot); >+ node->setResult(NodeResultInt32); >+ node->clearFlags(NodeMustGenerate); >+ fixIntConvertingEdge(operandEdge); > } >+ break; >+ } > >- fixIntConvertingEdge(node->child1()); >- node->clearFlags(NodeMustGenerate); >+ case ArithBitNot: { >+ Edge& operandEdge = node->child1(); >+ >+ fixIntConvertingEdge(operandEdge); > break; > } > >diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h >index b8014755c7bcb50914ed39d61a53d94aca86021e..3e9d16f2de880c6db7731a0b0e1405b72d6f43e8 100644 >--- a/Source/JavaScriptCore/dfg/DFGNode.h >+++ b/Source/JavaScriptCore/dfg/DFGNode.h >@@ -1363,6 +1363,11 @@ public: > return !!result(); > } > >+ bool hasInt32Result() >+ { >+ return result() == NodeResultInt32; >+ } >+ > bool hasInt52Result() > { > return result() == NodeResultInt52; >@@ -1372,6 +1377,11 @@ public: > { > return result() == NodeResultNumber; > } >+ >+ bool hasNumberOrAnyIntResult() >+ { >+ return hasNumberResult() || hasInt32Result() || hasInt52Result(); >+ } > > bool hasNumericResult() > { >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index dc2f3e16b832aac0af7f0ad63c4c8e281dcba34e..a503f9190a07569358faba3b0f3a3925fcf98397 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -111,7 +111,8 @@ namespace JSC { namespace DFG { > macro(InvalidationPoint, NodeMustGenerate) \ > \ > /* Nodes for bitwise operations. */\ >- macro(ArithBitNot, NodeResultInt32 | NodeMustGenerate) \ >+ macro(ValueBitNot, NodeResultJS | NodeMustGenerate) \ >+ macro(ArithBitNot, NodeResultInt32) \ > macro(ValueBitAnd, NodeResultJS | NodeMustGenerate) \ > macro(ArithBitAnd, NodeResultInt32) \ > macro(ValueBitOr, NodeResultJS | NodeMustGenerate) \ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index 1da406ba7e92767324201c788b3778b52e698819..03e673bdb9cc069631ed06a30dba5a446dcfedcc 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -360,10 +360,13 @@ EncodedJSValue JIT_OPERATION operationValueBitNot(ExecState* exec, EncodedJSValu > > JSValue op1 = JSValue::decode(encodedOp1); > >- int32_t operandValue = op1.toInt32(exec); >+ auto operandNumeric = op1.toBigIntOrInt32(exec); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); > >- return JSValue::encode(jsNumber(~operandValue)); >+ if (WTF::holds_alternative<JSBigInt*>(operandNumeric)) >+ RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::bitwiseNot(exec, WTF::get<JSBigInt*>(operandNumeric)))); >+ >+ return JSValue::encode(jsNumber(~WTF::get<int32_t>(operandNumeric))); > } > > EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) >@@ -381,11 +384,8 @@ EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState* exec, EncodedJSValu > RETURN_IF_EXCEPTION(scope, encodedJSValue()); > > if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- JSBigInt* result = JSBigInt::bitwiseAnd(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- return JSValue::encode(result); >- } >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) >+ RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::bitwiseAnd(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)))); > > return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'and' operation."); > } >@@ -408,11 +408,8 @@ EncodedJSValue JIT_OPERATION operationValueBitOr(ExecState* exec, EncodedJSValue > RETURN_IF_EXCEPTION(scope, encodedJSValue()); > > if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- JSBigInt* result = JSBigInt::bitwiseOr(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- return JSValue::encode(result); >- } >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) >+ RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::bitwiseOr(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)))); > > return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'or' operation."); > } >@@ -435,11 +432,8 @@ EncodedJSValue JIT_OPERATION operationValueBitXor(ExecState* exec, EncodedJSValu > RETURN_IF_EXCEPTION(scope, encodedJSValue()); > > if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- JSBigInt* result = JSBigInt::bitwiseXor(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- return JSValue::encode(result); >- } >+ if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) >+ RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::bitwiseXor(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)))); > > return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'xor' operation."); > } >@@ -527,9 +521,7 @@ EncodedJSValue JIT_OPERATION operationValueDiv(ExecState* exec, EncodedJSValue e > > if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) { > if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) { >- JSBigInt* result = JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- return JSValue::encode(result); >+ RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::divide(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)))); > } > > return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in division operation."); >@@ -1341,6 +1333,16 @@ JSCell* JIT_OPERATION operationSubBigInt(ExecState* exec, JSCell* op1, JSCell* o > return JSBigInt::sub(exec, leftOperand, rightOperand); > } > >+JSCell* JIT_OPERATION operationBitNotBigInt(ExecState* exec, JSCell* op1) >+{ >+ VM* vm = &exec->vm(); >+ NativeCallFrameTracer tracer(vm, exec); >+ >+ JSBigInt* operand = jsCast<JSBigInt*>(op1); >+ >+ return JSBigInt::bitwiseNot(exec, operand); >+} >+ > JSCell* JIT_OPERATION operationMulBigInt(ExecState* exec, JSCell* op1, JSCell* op2) > { > VM* vm = &exec->vm(); >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h >index 38c116a54f91a615b81c15112148f25f94adb1ef..97bf29123459c9d61ffc9ea431f0b9d10774ac75 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -170,6 +170,7 @@ JSCell* JIT_OPERATION operationSubBigInt(ExecState*, JSCell* op1, JSCell* op2) W > JSCell* JIT_OPERATION operationMulBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationDivBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationBitAndBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; >+JSCell* JIT_OPERATION operationBitNotBigInt(ExecState*, JSCell* op1) WTF_INTERNAL; > JSCell* JIT_OPERATION operationBitOrBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationAddBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationBitXorBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index b3c69bcf124727bfcc676b2afadab5a88c22f93a..1b63edabd379ac8644f5c195b3cf0e510926792c 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -277,6 +277,22 @@ private: > break; > } > >+ case ValueBitNot: { >+ SpeculatedType prediction = node->child1()->prediction(); >+ if (prediction) { >+ if (isBigIntSpeculation(prediction)) >+ changed |= mergePrediction(SpecBigInt); >+ else if (isInt32OrBooleanSpeculation(prediction) >+ || m_graph.unaryArithShouldSpeculateAnyInt(node, m_pass) >+ || isBytecodeNumberSpeculation(prediction)) >+ changed |= mergePrediction(SpecInt32Only); >+ else >+ changed |= mergePrediction(SpecInt32Only | SpecBigInt); >+ } >+ >+ break; >+ } >+ > case ValueBitXor: > case ValueBitOr: > case ValueBitAnd: { >@@ -1119,6 +1135,7 @@ private: > case ValueBitOr: > case ValueBitAnd: > case ValueBitXor: >+ case ValueBitNot: > case ValueNegate: > case ValueAdd: > case ValueSub: >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index f106982ae39ff3bcc36cfb5aee0d716c07e94316..053de19f95d079e769b0631621152e5166323aca 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -231,6 +231,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case ValueBitAnd: > case ValueBitXor: > case ValueBitOr: >+ case ValueBitNot: > case ValueNegate: > case ValueAdd: > case ValueSub: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index 63e09fb915ea97f04ae1f0f90e0e7f5c192bdd4f..4f7e790bd5f0ff32b232bc3c934d739e4dfd5ce0 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -3510,24 +3510,43 @@ void SpeculativeJIT::compileInstanceOf(Node* node) > return; > } > >-void SpeculativeJIT::compileBitwiseNot(Node* node) >+void SpeculativeJIT::compileValueBitNot(Node* node) > { > Edge& child1 = node->child1(); > >- if (child1.useKind() == UntypedUse) { >- JSValueOperand operand(this, child1); >- JSValueRegs operandRegs = operand.jsValueRegs(); >+ if (child1.useKind() == BigIntUse) { >+ SpeculateCellOperand operand(this, child1); >+ GPRReg operandGPR = operand.gpr(); >+ >+ speculateBigInt(child1, operandGPR); > > flushRegisters(); >- JSValueRegsFlushedCallResult result(this); >- JSValueRegs resultRegs = result.regs(); >- callOperation(operationValueBitNot, resultRegs, operandRegs); >+ GPRFlushedCallResult result(this); >+ GPRReg resultGPR = result.gpr(); >+ >+ callOperation(operationBitNotBigInt, resultGPR, operandGPR); > m_jit.exceptionCheck(); >+ cellResult(resultGPR, node); > >- jsValueResult(resultRegs, node); > return; > } > >+ 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); >+} >+ >+void SpeculativeJIT::compileBitwiseNot(Node* node) >+{ >+ Edge& child1 = node->child1(); >+ > SpeculateInt32Operand operand(this, child1); > GPRTemporary result(this); > GPRReg resultGPR = result.gpr(); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index dcdf9664fc4de580f87694d7fb78f5f8b6c6757a..80c16cd5a2717c34f45008545806e4b095d4e3ee 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1330,6 +1330,7 @@ public: > void compileUInt32ToNumber(Node*); > void compileDoubleAsInt32(Node*); > >+ void compileValueBitNot(Node*); > void compileBitwiseNot(Node*); > > template<typename SnippetGenerator, J_JITOperation_EJJ slowPathFunction> >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index fcda6a61f8bc74e7136982422476949f68a085eb..bd6029f7dd7c27d0030dbfd15d9ce92c9f8506bc 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -1991,6 +1991,10 @@ void SpeculativeJIT::compile(Node* node) > compileBitwiseOp(node); > break; > >+ case ValueBitNot: >+ compileValueBitNot(node); >+ break; >+ > case ArithBitNot: > compileBitwiseNot(node); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index 553f86f50675840823a16e5e58386f79bcac4f2e..567a7b6ef925adbe7d0def051eb0f9a59c722679 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2074,6 +2074,10 @@ void SpeculativeJIT::compile(Node* node) > recordSetLocal(dataFormatFor(node->variableAccessData()->flushFormat())); > break; > >+ case ValueBitNot: >+ compileValueBitNot(node); >+ break; >+ > case ArithBitNot: > compileBitwiseNot(node); > break; >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index 23c9396f4d69e04f6f0cb5f491ba04e6ccfad10a..367b907cf6fcc00fdb109770f2966abcfd23fda8 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -91,6 +91,7 @@ inline CapabilityLevel canCompile(Node* node) > case ValueBitAnd: > case ValueBitXor: > case ValueBitOr: >+ case ValueBitNot: > case ValueNegate: > case ValueAdd: > case ValueSub: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index 4130bd1ddb4d46f7fff9e1086309d55e5c9922c2..81e63c0f4c8365d341ffcc2bfccc8929304f00f5 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -659,6 +659,9 @@ private: > case ArithUnary: > compileArithUnary(); > break; >+ case ValueBitNot: >+ compileValueBitNot(); >+ break; > case ArithBitNot: > compileArithBitNot(); > break; >@@ -2881,15 +2884,23 @@ private: > } > } > >- void compileArithBitNot() >+ void compileValueBitNot() > { >- if (m_node->child1().useKind() == UntypedUse) { >- LValue operand = lowJSValue(m_node->child1()); >- LValue result = vmCall(Int64, m_out.operation(operationValueBitNot), m_callFrame, operand); >+ if (m_node->child1().useKind() == BigIntUse) { >+ LValue operand = lowBigInt(m_node->child1()); >+ >+ LValue result = vmCall(pointerType(), m_out.operation(operationBitNotBigInt), m_callFrame, operand); > setJSValue(result); > return; > } > >+ LValue operand = lowJSValue(m_node->child1()); >+ LValue result = vmCall(Int64, m_out.operation(operationValueBitNot), m_callFrame, operand); >+ setJSValue(result); >+ } >+ >+ void compileArithBitNot() >+ { > setInt32(m_out.bitNot(lowInt32(m_node->child1()))); > } > >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >index 3118b315a8cb8c5df2218d823381886cef582819..7aef09448a0e967cc50592af7fecb699384de0c2 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -722,9 +722,16 @@ SLOW_PATH_DECL(slow_path_bitnot) > { > BEGIN(); > auto bytecode = pc->as<OpBitnot>(); >- int32_t operand = GET_C(bytecode.operand).jsValue().toInt32(exec); >+ auto operandNumeric = GET_C(bytecode.operand).jsValue().toBigIntOrInt32(exec); > CHECK_EXCEPTION(); >- RETURN_PROFILED(jsNumber(~operand)); >+ >+ if (WTF::holds_alternative<JSBigInt*>(operandNumeric)) { >+ JSBigInt* result = JSBigInt::bitwiseNot(exec, WTF::get<JSBigInt*>(operandNumeric)); >+ CHECK_EXCEPTION(); >+ RETURN_PROFILED(result); >+ } >+ >+ RETURN_PROFILED(jsNumber(~WTF::get<int32_t>(operandNumeric))); > } > > SLOW_PATH_DECL(slow_path_bitand) >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.cpp b/Source/JavaScriptCore/runtime/JSBigInt.cpp >index ca531636b781e869ea78f76d25b5e4aead416185..127167879a8042637012d68d70bede37aefd75f2 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -525,6 +525,21 @@ JSBigInt* JSBigInt::signedRightShift(ExecState* exec, JSBigInt* x, JSBigInt* y) > return rightShiftByAbsolute(exec, x, y); > } > >+JSBigInt* JSBigInt::bitwiseNot(ExecState* exec, JSBigInt* x) >+{ >+ VM& vm = exec->vm(); >+ JSBigInt* result = nullptr; >+ if (x->sign()) { >+ // ~(-x) == ~(~(x-1)) == x-1 >+ result = absoluteSubOne(exec, x, x->length()); >+ } else { >+ // ~x == -x-1 == -(x+1) >+ result = absoluteAddOne(exec, x, SignOption::Signed); >+ } >+ >+ return result->rightTrim(vm); >+} >+ > #if USE(JSVALUE32_64) > #define HAVE_TWO_DIGIT 1 > typedef uint64_t TwoDigit; >diff --git a/Source/JavaScriptCore/runtime/JSBigInt.h b/Source/JavaScriptCore/runtime/JSBigInt.h >index 2b3bf9307d8dbbb1107533ed830347bcdd4a610b..8aa94427e35e821a8bf81b1df73da741793b37d3 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -123,6 +123,7 @@ public: > static JSBigInt* bitwiseAnd(ExecState*, JSBigInt* x, JSBigInt* y); > static JSBigInt* bitwiseOr(ExecState*, JSBigInt* x, JSBigInt* y); > static JSBigInt* bitwiseXor(ExecState*, JSBigInt* x, JSBigInt* y); >+ static JSBigInt* bitwiseNot(ExecState*, JSBigInt* x); > > static JSBigInt* leftShift(ExecState*, JSBigInt* x, JSBigInt* y); > static JSBigInt* signedRightShift(ExecState*, JSBigInt* x, JSBigInt* y); >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 9e350a323faf25b7963d0be326807ff5799ed587..e1d903d7c45a274dcbbba1c16c4e0bf22e19c850 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,15 @@ >+2018-12-25 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement "~" unary operation >+ https://bugs.webkit.org/show_bug.cgi?id=182216 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * stress/big-int-bit-not-general.js: Added. >+ * stress/big-int-bitwise-not-jit.js: Added. >+ * stress/big-int-bitwise-not-wrapped-value.js: Added. >+ * stress/bitwise-not-fixup-rules.js: Added. >+ > 2018-12-13 Yusuke Suzuki <yusukesuzuki@slowstart.org> > > [BigInt] Support BigInt in JSON.stringify >diff --git a/JSTests/stress/big-int-bit-not-general.js b/JSTests/stress/big-int-bit-not-general.js >new file mode 100644 >index 0000000000000000000000000000000000000000..07eb056479a8588ce8fdb0497ba31d9273c37609 >--- /dev/null >+++ b/JSTests/stress/big-int-bit-not-general.js >@@ -0,0 +1,39 @@ >+//@ runBigIntEnabled >+ >+// Copyright (C) 2017 Josh Wolfe. All rights reserved. >+// This code is governed by the BSD license found in the LICENSE file. >+ >+function assert(a) { >+ if (!a) >+ throw new Error("Bad assertion"); >+} >+ >+assert.sameValue = function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+} >+ >+assert.sameValue(~0n, -1n, "~0n === -1n"); >+assert.sameValue(~(0n), -1n, "~(0n) === -1n"); >+assert.sameValue(~1n, -2n, "~1n === -2n"); >+assert.sameValue(~-1n, 0n, "~-1n === 0n"); >+assert.sameValue(~(-1n), 0n, "~(-1n) === 0n"); >+assert.sameValue(~~1n, 1n, "~~1n === 1n"); >+assert.sameValue(~0x5an, -0x5bn, "~0x5an === -0x5bn"); >+assert.sameValue(~-0x5an, 0x59n, "~-0x5an === 0x59n"); >+assert.sameValue(~0xffn, -0x100n, "~0xffn === -0x100n"); >+assert.sameValue(~-0xffn, 0xfen, "~-0xffn === 0xfen"); >+assert.sameValue(~0xffffn, -0x10000n, "~0xffffn === -0x10000n"); >+assert.sameValue(~-0xffffn, 0xfffen, "~-0xffffn === 0xfffen"); >+assert.sameValue(~0xffffffffn, -0x100000000n, "~0xffffffffn === -0x100000000n"); >+assert.sameValue(~-0xffffffffn, 0xfffffffen, "~-0xffffffffn === 0xfffffffen"); >+assert.sameValue( >+ ~0xffffffffffffffffn, -0x10000000000000000n, >+ "~0xffffffffffffffffn === -0x10000000000000000n"); >+assert.sameValue( >+ ~-0xffffffffffffffffn, 0xfffffffffffffffen, >+ "~-0xffffffffffffffffn === 0xfffffffffffffffen"); >+assert.sameValue( >+ ~0x123456789abcdef0fedcba9876543210n, -0x123456789abcdef0fedcba9876543211n, >+ "~0x123456789abcdef0fedcba9876543210n === -0x123456789abcdef0fedcba9876543211n"); >+ >diff --git a/JSTests/stress/big-int-bitwise-not-jit.js b/JSTests/stress/big-int-bitwise-not-jit.js >new file mode 100644 >index 0000000000000000000000000000000000000000..d761e1f75976a54cacdc0de2d205c19b7183b5f3 >--- /dev/null >+++ b/JSTests/stress/big-int-bitwise-not-jit.js >@@ -0,0 +1,19 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntBitNot(a) { >+ return ~(~a); >+} >+noInline(bigIntBitNot); >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntBitNot(3n); >+ assert.sameValue(r, 3n, "~~" + 3n + " = " + r); >+} >+ >diff --git a/JSTests/stress/big-int-bitwise-not-wrapped-value.js b/JSTests/stress/big-int-bitwise-not-wrapped-value.js >new file mode 100644 >index 0000000000000000000000000000000000000000..1bc571bd029a6040a0278f5b1b9aa6a2fd5f30e3 >--- /dev/null >+++ b/JSTests/stress/big-int-bitwise-not-wrapped-value.js >@@ -0,0 +1,36 @@ >+//@ runBigIntEnabled >+ >+assert = { >+ sameValue: function (input, expected, message) { >+ if (input !== expected) >+ throw new Error(message); >+ } >+}; >+ >+function testBitNot(x, z, message) { >+ assert.sameValue(~x, z, message); >+} >+ >+testBitNot(Object(1n), -2n, "ToPrimitive: unbox object with internal slot"); >+ >+let o = { >+ [Symbol.toPrimitive]: function() { >+ return 1n; >+ } >+}; >+testBitNot(o, -2n, "ToPrimitive: @@toPrimitive"); >+ >+o = { >+ valueOf: function() { >+ return 1n; >+ } >+}; >+testBitNot(o, -2n, "ToPrimitive: valueOf"); >+ >+o = { >+ toString: function() { >+ return 1n; >+ } >+} >+testBitNot(o, -2n, "ToPrimitive: toString"); >+ >diff --git a/JSTests/stress/bitwise-not-fixup-rules.js b/JSTests/stress/bitwise-not-fixup-rules.js >new file mode 100644 >index 0000000000000000000000000000000000000000..62be62a4ea70397a72b0def6241cf201ee9c277e >--- /dev/null >+++ b/JSTests/stress/bitwise-not-fixup-rules.js >@@ -0,0 +1,27 @@ >+//@ runBigIntEnabled >+ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected to be: " + e + " but got: " + a); >+} >+ >+function foo(a) { >+ return ~a; >+} >+noInline(foo); >+ >+let c = 0; >+let o = { >+ valueOf: () => { >+ c++; >+ return 3; >+ } >+}; >+ >+for (let i = 0; i < 10000; i++) >+ foo(o); >+ >+assert(c, 10000); >+if (numberOfDFGCompiles(foo) > 1) >+ throw new Error("Function 'foo' should be compiled just once"); >+ >diff --git a/PerformanceTests/BigIntBench/big-int-simple-bit-not.js b/PerformanceTests/BigIntBench/big-int-simple-bit-not.js >new file mode 100644 >index 0000000000000000000000000000000000000000..488a70d4f74038a1eaad5aab0d744cb431137f19 >--- /dev/null >+++ b/PerformanceTests/BigIntBench/big-int-simple-bit-not.js >@@ -0,0 +1,15 @@ >+function bigInt(a, b) { >+ let c = ~a; >+ return ~a + ~c; >+} >+noInline(bigInt); >+ >+for (let i = 0; i < 100000; i++) { >+ bigInt(0b1111n, 0b1010n); >+} >+ >+let out; >+for (let i = 0; i < 100000; i++) { >+ out = bigInt(0xffffffffffffffffffn, 0xaaffffffffffffffffffn); >+} >+ >diff --git a/PerformanceTests/ChangeLog b/PerformanceTests/ChangeLog >index e3244041bc49a8815d701b362cb647c454178d54..fc7e15bb5b41f9f84c6e3416aaaf81796c133291 100644 >--- a/PerformanceTests/ChangeLog >+++ b/PerformanceTests/ChangeLog >@@ -1,3 +1,12 @@ >+2018-12-25 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext][BigInt] Implement "~" unary operation >+ https://bugs.webkit.org/show_bug.cgi?id=182216 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * BigIntBench/big-int-simple-bit-not.js: Added. >+ > 2018-12-20 Caio Lima <ticaiolima@gmail.com> > > [BigInt] We should enable CSE into arithmetic operations that speculate BigIntUse
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 182216
:
356382
|
356489
|
356498
|
357224
|
357227
|
358064
|
359198
|
359235
|
359236
|
359885
|
359890
|
359898
|
360006
|
360007
|
360931
|
362250
|
363089
|
363878
|
364004