WebKit Bugzilla
Attachment 360931 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-20190201234036.patch (text/plain), 34.89 KB, created by
Caio Lima
on 2019-02-01 17:40:48 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2019-02-01 17:40:48 PST
Size:
34.89 KB
patch
obsolete
>Subversion Revision: 240887 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index d021748c656098946963b214db46718f6b85a03b..da47571db9e0d3b83b1a8140dc6b3d9059a6cff5 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,57 @@ >+2019-02-01 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-01 Mark Lam <mark.lam@apple.com> > > Remove invalid assertion in DFG's compileDoubleRep(). >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index 7581a1a7746e9870e79f92e2178fbd2c9759226d..e67ddb684da15e338639d7a07f7c6ed9c7c1377d 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 b1dc25b1b878f0b5d4f4d41d41df1fdad92362a4..d2415b0ecbf8121d740f31c2075f36f6407f12cc 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 7e9b0d8969aceaa0fca1039b0bcc746beb7b9533..5c8b939739b7bc897a41a9794788cae856119856 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 191f26b1a8e76b4589a8c0937159e68be6b6d213..75bd7722617a0a7c2d1cb0e84b446bba214cb09b 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -380,6 +380,7 @@ bool doesGC(Graph& graph, Node* node) > case ValueSub: > case ValueMul: > case ValueDiv: >+ case ValueBitNot: > return true; > > case CallStringConstructor: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index d2d4fbfb44b35715358ca71e46f1ed20c68e2be2..24dce987df26ffe2e372db47fff08c4ed129253d 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 4c7deb6ad68ab008c2a663b9e413f710a2ade36a..d7b6a5b3005f741520ac54e661c971e932687154 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 bd3bfe2fd40d2d0bd3b1d307a43a122935284e43..6b109eb12ce6835649f943e9b2624b565a3db94a 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 22750b7997af9c9a6b0eea3a5acfced1458c7f2e..c206d3cf5ee0c53fae09b78e0274933a0e0660e0 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) >@@ -1338,6 +1326,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 9ec916f2ea05972f666a9b2132806fee4aef595d..8d9f67bcc1f714eb844b8af0a50173eb7bb201cf 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 7f9e381b755d264ca75e3e7dcaca80c8741dde66..1fbf0ec5ee03029e97ca66b754a2d48252b33cb7 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 1ff0c337da8c95ce94c56f8ebe3a9b6a4e4dab15..6920b7a031a0b19f0f12742fb4e23ebb2073866c 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 4f3a5a054b58b145c70c8a4a6a4af6cc0f5a0807..bd45df49f00a8c8433eecce063221e8e3c279b5d 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 bbbadab67fdf6fcad4cac0664cdc8e60bf5e4b2e..d31163d00f4ff44e729172874671018045b3b436 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -723,9 +723,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 8d03fbcb633452c30d9f27c318942f57c9641de6..7ba4b894f80e727b99c0a6b5099bf6712b0d14d6 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,16 @@ >+2019-02-01 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-01 Mark Lam <mark.lam@apple.com> > > Remove invalid assertion in DFG's compileDoubleRep(). >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 7aac53b9ed32ec6aee94df7a627a250224cb90e2..29cc434fe3b1c0b51c274e405b0fbe8823256458 100644 >--- a/PerformanceTests/ChangeLog >+++ b/PerformanceTests/ChangeLog >@@ -1,3 +1,12 @@ >+2019-02-01 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-01-31 Sihui Liu <sihui_liu@apple.com> > > REGRESSION (r240358): IndexedDB/large-binary-keys.html and IndexedDB/large-string-keys.html perf tests failing
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