WebKit Bugzilla
Attachment 362250 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-20190217190304.patch (text/plain), 34.92 KB, created by
Caio Lima
on 2019-02-17 14:03:12 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2019-02-17 14:03:12 PST
Size:
34.92 KB
patch
obsolete
>Subversion Revision: 241651 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 165c1820f75845e5e77b2981132b8a8ff9decd53..002f20e4b7c24a01e5e68f8baf46fcff23ceec64 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,57 @@ >+2019-02-17 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::hasHeapPrediction): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOperations.cpp: >+ (JSC::DFG::bitwiseBinaryOp): >+ * 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: >+ > 2019-02-17 Commit Queue <commit-queue@webkit.org> > > Unreviewed, rolling out r241612. >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 67e5a87cb3880dfe5bfca58615ef3bbab3d08ad6..97b43b365e6418ca8b7998a95c16369c922fb24b 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -376,13 +376,27 @@ 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(); >+ if (node->child1().useKind() == UntypedUse) >+ 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 f4ce71eba58adbd5b36109e6fb6b32962cdd72f9..6ecc199d72670bdfa96e0b1b24da48c0f36c5279 100644 >--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >@@ -210,6 +210,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 77840e89c54e81e287fb3f653ce758ea8d20a080..a630c5707cdaa6d711d7cae0a3dad844d4415b3d 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -4918,8 +4918,12 @@ void ByteCodeParser::parseBlock(unsigned limit) > > case op_bitnot: { > auto bytecode = currentInstruction->as<OpBitnot>(); >+ SpeculatedType prediction = getPrediction(); > Node* op1 = get(bytecode.m_operand); >- set(bytecode.m_dst, addToGraph(ArithBitNot, op1)); >+ if (op1->hasNumberOrAnyIntResult()) >+ set(bytecode.m_dst, addToGraph(ArithBitNot, op1)); >+ else >+ set(bytecode.m_dst, addToGraph(ValueBitNot, OpInfo(), OpInfo(prediction), op1)); > NEXT_OPCODE(op_bitnot); > } > >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index add1499e8a69ae192a13d1761ffbd27b72bd8f7a..3725d63762dd2afc7424dd67eff89c0d03c7e91a 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -259,6 +259,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 1598f7e85809bd769c9891958aeaff69e66a0386..d4d5eaba28b8e02f5df1654ab68d5628bc95f519 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -384,6 +384,7 @@ bool doesGC(Graph& graph, Node* node) > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValueBitNot: > case ValueNegate: > #else > // See comment at the top for why be default for all nodes should be to >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index c68d6e2dd8d4e7ea338a6a7b54be5150588f3df2..f6448ebf392837c3abf6faace3d7e1ee06da3e43 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -234,14 +234,27 @@ private: > break; > } > >- case ArithBitNot: { >- if (node->child1().node()->shouldSpeculateUntypedForBitOps()) { >- fixEdge<UntypedUse>(node->child1()); >- break; >+ case ValueBitNot: { >+ Edge& operandEdge = node->child1(); >+ >+ if (operandEdge.node()->shouldSpeculateBigInt()) { >+ node->clearFlags(NodeMustGenerate); >+ 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 fb3679a0b298b3b58739da905e2c1be64f84fb4a..211dd0b3ceccb84755eb36d67ecc4166709da7a3 100644 >--- a/Source/JavaScriptCore/dfg/DFGNode.h >+++ b/Source/JavaScriptCore/dfg/DFGNode.h >@@ -1693,6 +1693,7 @@ public: > case ValueBitAnd: > case ValueBitOr: > case ValueBitXor: >+ case ValueBitNot: > case CallObjectConstructor: > case LoadKeyFromMapBucket: > case LoadValueFromMapBucket: >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index ef63cdb446c74af9c66631ef3b17b28469590d59..95d13a3248135fcbb7ce97c9fd3ab395e1db513e 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 6a578266eb4a128327e53cdaacb7d861577c49ef..dc3750579f09e2e617d61bd9b4f945b780ab66c0 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -212,6 +212,33 @@ static ALWAYS_INLINE void putWithThis(ExecState* exec, EncodedJSValue encodedBas > baseValue.putInline(exec, ident, putValue, slot); > } > >+template<typename BigIntOperation, typename Int32Operation> >+static ALWAYS_INLINE EncodedJSValue bitwiseBinaryOp(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BigIntOperation&& bigIntOp, Int32Operation&& int32Op, const char* errorMessage) >+{ >+ VM* vm = &exec->vm(); >+ NativeCallFrameTracer tracer(vm, exec); >+ auto scope = DECLARE_THROW_SCOPE(*vm); >+ >+ JSValue op1 = JSValue::decode(encodedOp1); >+ JSValue op2 = JSValue::decode(encodedOp2); >+ >+ auto leftNumeric = op1.toBigIntOrInt32(exec); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ auto rightNumeric = op2.toBigIntOrInt32(exec); >+ 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)) >+ RELEASE_AND_RETURN(scope, JSValue::encode(bigIntOp(exec, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric)))); >+ >+ return throwVMTypeError(exec, scope, errorMessage); >+ } >+ >+ scope.release(); >+ >+ return JSValue::encode(jsNumber(int32Op(WTF::get<int32_t>(leftNumeric), WTF::get<int32_t>(rightNumeric)))); >+} >+ > static ALWAYS_INLINE EncodedJSValue parseIntResult(double input) > { > int asInt = static_cast<int>(input); >@@ -360,91 +387,52 @@ 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) > { >- VM* vm = &exec->vm(); >- NativeCallFrameTracer tracer(vm, exec); >- auto scope = DECLARE_THROW_SCOPE(*vm); >+ auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* { >+ return JSBigInt::bitwiseAnd(exec, left, right); >+ }; > >- JSValue op1 = JSValue::decode(encodedOp1); >- JSValue op2 = JSValue::decode(encodedOp2); >- >- auto leftNumeric = op1.toBigIntOrInt32(exec); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- auto rightNumeric = op2.toBigIntOrInt32(exec); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ auto int32Op = [] (int32_t left, int32_t right) -> int32_t { >+ return left & right; >+ }; > >- 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); >- } >- >- return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'and' operation."); >- } >- >- return JSValue::encode(jsNumber(WTF::get<int32_t>(leftNumeric) & WTF::get<int32_t>(rightNumeric))); >+ return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'and' operation."); > } > > EncodedJSValue JIT_OPERATION operationValueBitOr(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) > { >- VM* vm = &exec->vm(); >- NativeCallFrameTracer tracer(vm, exec); >- auto scope = DECLARE_THROW_SCOPE(*vm); >+ auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* { >+ return JSBigInt::bitwiseOr(exec, left, right); >+ }; > >- JSValue op1 = JSValue::decode(encodedOp1); >- JSValue op2 = JSValue::decode(encodedOp2); >+ auto int32Op = [] (int32_t left, int32_t right) -> int32_t { >+ return left | right; >+ }; > >- auto leftNumeric = op1.toBigIntOrInt32(exec); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- auto rightNumeric = op2.toBigIntOrInt32(exec); >- 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); >- } >- >- return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'or' operation."); >- } >- >- return JSValue::encode(jsNumber(WTF::get<int32_t>(leftNumeric) | WTF::get<int32_t>(rightNumeric))); >+ return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'or' operation."); > } > > EncodedJSValue JIT_OPERATION operationValueBitXor(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) > { >- VM* vm = &exec->vm(); >- NativeCallFrameTracer tracer(vm, exec); >- auto scope = DECLARE_THROW_SCOPE(*vm); >+ auto bigIntOp = [] (ExecState* exec, JSBigInt* left, JSBigInt* right) -> JSBigInt* { >+ return JSBigInt::bitwiseXor(exec, left, right); >+ }; > >- JSValue op1 = JSValue::decode(encodedOp1); >- JSValue op2 = JSValue::decode(encodedOp2); >+ auto int32Op = [] (int32_t left, int32_t right) -> int32_t { >+ return left ^ right; >+ }; > >- auto leftNumeric = op1.toBigIntOrInt32(exec); >- RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- auto rightNumeric = op2.toBigIntOrInt32(exec); >- 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); >- } >- >- return throwVMTypeError(exec, scope, "Invalid mix of BigInt and other type in bitwise 'xor' operation."); >- } >- >- return JSValue::encode(jsNumber(WTF::get<int32_t>(leftNumeric) ^ WTF::get<int32_t>(rightNumeric))); >+ return bitwiseBinaryOp(exec, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'xor' operation."); > } > > EncodedJSValue JIT_OPERATION operationValueBitLShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) >@@ -1333,6 +1321,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 c2afe5b378add7ae4d1e9bd4fd8320ae27687065..206d424bb00887d9873c6400ac2b13e136bcaca7 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -802,6 +802,7 @@ private: > case ValueBitAnd: > case ValueBitXor: > case ValueBitOr: >+ case ValueBitNot: > case CallObjectConstructor: > case GetArgument: > case CallDOMGetter: >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index 883f79988bd6a4a4c2735173bc5c598c5a77666d..1cf15c4b5a0e1978027f081abe349aa13f0e246f 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 2911288ede8d5699066d0d11ff2b7fd4b29de121..484aebb532c9191a1605133a91befb3dd9dfb1e5 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -3508,24 +3508,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 8ed85f6311f14a940530e2f146288ab612b10b3d..b83fbf004ff1f4f282622f0d12325365b6630717 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 4dfe9c92321d753d178148f4ed35f8973f3e6f52..30865e992d02844657a591373430e8ea80178328 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 63052becc0508d6d2927cb0060b4be87626976a1..2c2b1835789e518c8462a7b00e4b1eb43bfebef8 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 535721296925a9009042f111048a9986f8b7d220..8aeaca79356115fc41e7ea5cf8617d83ad3c0187 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 a17f95421f7c30b5704e77d2ffd8a6a90317e1b1..e910e2ced0b8fc3c9af60da3cd86eadd94a30d80 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; >@@ -2884,15 +2887,22 @@ 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 5871c930bbc8e06636110ea4c6769b202340751d..305441918f72ad6077ba1cab8bfa7f0f9da31bd7 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -715,9 +715,16 @@ SLOW_PATH_DECL(slow_path_bitnot) > { > BEGIN(); > auto bytecode = pc->as<OpBitnot>(); >- int32_t operand = GET_C(bytecode.m_operand).jsValue().toInt32(exec); >+ auto operandNumeric = GET_C(bytecode.m_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 2bcaa9b6762d252f0b31ee1a8949cdd83746800e..c588e3fe1b308b57a06fde3fccb53b0d18caadd3 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.cpp >+++ b/Source/JavaScriptCore/runtime/JSBigInt.cpp >@@ -525,6 +525,16 @@ JSBigInt* JSBigInt::signedRightShift(ExecState* exec, JSBigInt* x, JSBigInt* y) > return rightShiftByAbsolute(exec, x, y); > } > >+JSBigInt* JSBigInt::bitwiseNot(ExecState* exec, JSBigInt* x) >+{ >+ if (x->sign()) { >+ // ~(-x) == ~(~(x-1)) == x-1 >+ return absoluteSubOne(exec, x, x->length()); >+ } >+ // ~x == -x-1 == -(x+1) >+ return absoluteAddOne(exec, x, SignOption::Signed); >+} >+ > #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 dbbf63ded1c8cbd48ea7b9fcb5b0e8515b5fea9d..eacf7065e0fb1bbcd2e5f4ee8baeca74beb69753 100644 >--- a/Source/JavaScriptCore/runtime/JSBigInt.h >+++ b/Source/JavaScriptCore/runtime/JSBigInt.h >@@ -124,6 +124,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 1c9bc23e4b40e5abcc4f8259e6abe2734f8fe86d..3b39abcb6b207e4feb5c4025a16d3569978ef0e0 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,16 @@ >+2019-02-17 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/bit-op-with-object-returning-int32.js: >+ * stress/bitwise-not-fixup-rules.js: Added. >+ > 2019-02-15 Michael Saboff <msaboff@apple.com> > > RELEASE_ASSERT at com.apple.JavaScriptCore: JSC::jsSubstringOfResolved >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..7f4a5dfe56a069853052ebc0bee792d9629a946b >--- /dev/null >+++ b/JSTests/stress/big-int-bitwise-not-wrapped-value.js >@@ -0,0 +1,59 @@ >+//@ 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"); >+ >+// Test priority >+ >+function badAssertion() { >+ throw new Error("This should never be called"); >+} >+ >+o = { >+ [Symbol.toPrimitive]: function() { >+ return 1n; >+ }, >+ valueOf: badAssertion, >+ toString: badAssertion >+}; >+testBitNot(o, -2n, "ToPrimitive: @@toPrimitive and others throw"); >+ >+o = { >+ valueOf: function() { >+ return 1n; >+ }, >+ toString: badAssertion >+}; >+testBitNot(o, -2n, "ToPrimitive: valueOf and toString throws"); >+ >diff --git a/JSTests/stress/bit-op-with-object-returning-int32.js b/JSTests/stress/bit-op-with-object-returning-int32.js >index 7e9134498e9b751c1dbad26b157e04a520c67274..1749afbc50a4f47a93cfc6e66e5729761c24bb27 100644 >--- a/JSTests/stress/bit-op-with-object-returning-int32.js >+++ b/JSTests/stress/bit-op-with-object-returning-int32.js >@@ -36,3 +36,13 @@ for (var i = 0; i < 10000; i++) > > assert(numberOfDFGCompiles(bitXor) <= 1, true); > >+function bitNot(a) { >+ return ~a; >+} >+noInline(bitNot); >+ >+for (var i = 0; i < 10000; i++) >+ assert(bitNot(o), -14); >+ >+assert(numberOfDFGCompiles(bitNot) <= 1, true); >+ >diff --git a/JSTests/stress/bitwise-not-fixup-rules.js b/JSTests/stress/bitwise-not-fixup-rules.js >new file mode 100644 >index 0000000000000000000000000000000000000000..ead2ce24b0b5888df1ddd575f70100ed812e8a8c >--- /dev/null >+++ b/JSTests/stress/bitwise-not-fixup-rules.js >@@ -0,0 +1,27 @@ >+//@ if $jitTests then runBigIntEnabled else skip end >+ >+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 d6d63135d0f5d951ad9f968eb3991e3ca70f4a1b..8384a561a7349e4bd9a3acf3c849e6674fcaf32a 100644 >--- a/PerformanceTests/ChangeLog >+++ b/PerformanceTests/ChangeLog >@@ -1,3 +1,12 @@ >+2019-02-17 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. >+ > 2019-02-08 Saam barati <sbarati@apple.com> > > Update JetStream2 CLI to not print "ms" since we now just print the score values
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