WebKit Bugzilla
Attachment 357118 Details for
Bug 186178
: [BigInt] Add ValueDiv into DFG
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-186178-20181212115719.patch (text/plain), 38.60 KB, created by
Caio Lima
on 2018-12-12 05:57:21 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2018-12-12 05:57:21 PST
Size:
38.60 KB
patch
obsolete
>Subversion Revision: 239045 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 1c7995865f6dfd00fa230c6d7b18ea523111cbe6..c619e780428dd535f7536c853977f75315850e20 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,65 @@ >+2018-12-12 Caio Lima <ticaiolima@gmail.com> >+ >+ [BigInt] Add ValueDiv into DFG >+ https://bugs.webkit.org/show_bug.cgi?id=186178 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch is introducing a new node type called ValueDiv. This node >+ is responsible to handle Untyped and Bigint specialization of division >+ operator, while the ArithDiv variant handles Number/Boolean cases. >+ >+ BigInt specialization generates following speedup into simple >+ benchmark: >+ >+ noSpec changes >+ >+ big-int-simple-div 10.6013+-0.4682 ^ 8.4518+-0.0943 ^ definitely 1.2543x faster >+ >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGBackwardsPropagationPhase.cpp: >+ (JSC::DFG::BackwardsPropagationPhase::propagate): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::makeDivSafe): >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGDoesGC.cpp: >+ (JSC::DFG::doesGC): >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupArithDiv): >+ (JSC::DFG::FixupPhase::fixupNode): >+ * dfg/DFGNode.h: >+ (JSC::DFG::Node::arithNodeFlags): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOperations.cpp: >+ * dfg/DFGOperations.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT.cpp: >+ (JSC::DFG::SpeculativeJIT::compileValueDiv): >+ (JSC::DFG::SpeculativeJIT::compileArithDiv): >+ * dfg/DFGSpeculativeJIT.h: >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGValidate.cpp: >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileNode): >+ (JSC::FTL::DFG::LowerDFGToB3::compileValueAdd): >+ (JSC::FTL::DFG::LowerDFGToB3::compileValueSub): >+ (JSC::FTL::DFG::LowerDFGToB3::compileValueDiv): >+ (JSC::FTL::DFG::LowerDFGToB3::compileArithDiv): >+ (JSC::FTL::DFG::LowerDFGToB3::compileArithBitNot): >+ (JSC::FTL::DFG::LowerDFGToB3::compileValueBitAnd): >+ (JSC::FTL::DFG::LowerDFGToB3::compileValueBitOr): >+ (JSC::FTL::DFG::LowerDFGToB3::compileValueBitXor): >+ > 2018-12-10 Caio Lima <ticaiolima@gmail.com> > > [BigInt] Add ValueMul into DFG >diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >index c8f66dde246ac8dcc5736cc65466ba812932b963..5428bc9257f82ef9e0eb5b99bec99090fa378f06 100644 >--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >@@ -913,6 +913,15 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > break; > } > >+ case ValueDiv: { >+ clobberWorld(); >+ if (node->binaryUseKind() == BigIntUse) >+ setTypeForNode(node, SpecBigInt); >+ else >+ setTypeForNode(node, SpecBytecodeNumber | SpecBigInt); >+ break; >+ } >+ > case ArithDiv: { > JSValue left = forNode(node->child1()).value(); > JSValue right = forNode(node->child2()).value(); >@@ -941,10 +950,6 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi > typeOfDoubleQuotient( > forNode(node->child1()).m_type, forNode(node->child2()).m_type)); > break; >- case UntypedUse: >- clobberWorld(); >- setNonCellTypeForNode(node, SpecBytecodeNumber); >- break; > default: > RELEASE_ASSERT_NOT_REACHED(); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >index 2d8c514d8f834f4b09ba7812f6af04b5d73c9642..05c86ed1eb05f129ed4d00206d31e4e1f25d6159 100644 >--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp >@@ -346,6 +346,7 @@ private: > break; > } > >+ case ValueDiv: > case ArithDiv: { > flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero; > flags &= ~NodeBytecodeUsesAsOther; >diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >index aa23167327c6de6814614a2a314b5b7a2f03d0b8..c65cc200400a69fb66871c856dd7f8b508205d0b 100644 >--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >@@ -1004,7 +1004,7 @@ private: > > Node* makeDivSafe(Node* node) > { >- ASSERT(node->op() == ArithDiv); >+ ASSERT(node->op() == ArithDiv || node->op() == ValueDiv); > > if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) > node->mergeFlags(NodeMayOverflowInt32InDFG); >@@ -1023,6 +1023,10 @@ private: > // FIXME: It might be possible to make this more granular. > node->mergeFlags(NodeMayOverflowInt32InBaseline | NodeMayNegZeroInBaseline); > >+ ArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->arithProfileForBytecodeOffset(m_currentIndex); >+ if (arithProfile->didObserveBigInt()) >+ node->mergeFlags(NodeMayHaveBigIntResult); >+ > return node; > } > >@@ -5049,7 +5053,10 @@ void ByteCodeParser::parseBlock(unsigned limit) > auto bytecode = currentInstruction->as<OpDiv>(); > Node* op1 = get(bytecode.lhs); > Node* op2 = get(bytecode.rhs); >- set(bytecode.dst, makeDivSafe(addToGraph(ArithDiv, op1, op2))); >+ if (op1->hasNumberResult() && op2->hasNumberResult()) >+ set(bytecode.dst, makeDivSafe(addToGraph(ArithDiv, op1, op2))); >+ else >+ set(bytecode.dst, makeDivSafe(addToGraph(ValueDiv, op1, op2))); > NEXT_OPCODE(op_div); > } > >diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h >index 95404f3f920dd99d6311875feb82a9ba393b2b64..ac65f09c656ac4496580ae8190abf87f45130b68 100644 >--- a/Source/JavaScriptCore/dfg/DFGClobberize.h >+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h >@@ -651,6 +651,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu > case ValueAdd: > case ValueSub: > case ValueMul: >+ case ValueDiv: > case SetFunctionName: > case GetDynamicVar: > case PutDynamicVar: >diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >index 64e2f5efecad64b3013d4189e2849cb153498f69..7a263ab9c85d3b3a6427436f48769a4ac033c87e 100644 >--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp >@@ -104,6 +104,7 @@ bool doesGC(Graph& graph, Node* node) > case ValueSub: > case ValueMul: > case ValueNegate: >+ case ValueDiv: > case TryGetById: > case GetById: > case GetByIdFlush: >diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >index 5b0de12fa5067183c6b886f11fc0cb04980cb91c..c8bcbffdccbd2ad343514d8a147b8d6af515350e 100644 >--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >@@ -76,6 +76,44 @@ public: > } > > private: >+ void fixupArithDiv(Node* node, Edge& leftChild, Edge& rightChild) >+ { >+ if (m_graph.binaryArithShouldSpeculateInt32(node, FixupPass)) { >+ if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7IDIVSupported()) { >+ fixIntOrBooleanEdge(leftChild); >+ fixIntOrBooleanEdge(rightChild); >+ if (bytecodeCanTruncateInteger(node->arithNodeFlags())) >+ node->setArithMode(Arith::Unchecked); >+ else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) >+ node->setArithMode(Arith::CheckOverflow); >+ else >+ node->setArithMode(Arith::CheckOverflowAndNegativeZero); >+ return; >+ } >+ >+ // This will cause conversion nodes to be inserted later. >+ fixDoubleOrBooleanEdge(leftChild); >+ fixDoubleOrBooleanEdge(rightChild); >+ >+ // We don't need to do ref'ing on the children because we're stealing them from >+ // the original division. >+ Node* newDivision = m_insertionSet.insertNode(m_indexInBlock, SpecBytecodeDouble, *node); >+ newDivision->setResult(NodeResultDouble); >+ >+ node->setOp(DoubleAsInt32); >+ node->children.initialize(Edge(newDivision, DoubleRepUse), Edge(), Edge()); >+ if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) >+ node->setArithMode(Arith::CheckOverflow); >+ else >+ node->setArithMode(Arith::CheckOverflowAndNegativeZero); >+ return; >+ } >+ >+ fixDoubleOrBooleanEdge(leftChild); >+ fixDoubleOrBooleanEdge(rightChild); >+ node->setResult(NodeResultDouble); >+ } >+ > void fixupArithMul(Node* node, Edge& leftChild, Edge& rightChild) > { > if (m_graph.binaryArithShouldSpeculateInt32(node, FixupPass)) { >@@ -454,52 +492,34 @@ private: > break; > } > >- case ArithDiv: >- case ArithMod: { >+ case ValueDiv: { > Edge& leftChild = node->child1(); > Edge& rightChild = node->child2(); >- if (op == ArithDiv >- && Node::shouldSpeculateUntypedForArithmetic(leftChild.node(), rightChild.node()) >- && m_graph.hasExitSite(node->origin.semantic, BadType)) { >+ >+ if (Node::shouldSpeculateBigInt(leftChild.node(), rightChild.node())) { >+ fixEdge<BigIntUse>(leftChild); >+ fixEdge<BigIntUse>(rightChild); >+ break; >+ } >+ >+ if (Node::shouldSpeculateUntypedForArithmetic(leftChild.node(), rightChild.node())) { > fixEdge<UntypedUse>(leftChild); > fixEdge<UntypedUse>(rightChild); >- node->setResult(NodeResultJS); > break; > } >- if (m_graph.binaryArithShouldSpeculateInt32(node, FixupPass)) { >- if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7IDIVSupported()) { >- fixIntOrBooleanEdge(leftChild); >- fixIntOrBooleanEdge(rightChild); >- if (bytecodeCanTruncateInteger(node->arithNodeFlags())) >- node->setArithMode(Arith::Unchecked); >- else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) >- node->setArithMode(Arith::CheckOverflow); >- else >- node->setArithMode(Arith::CheckOverflowAndNegativeZero); >- break; >- } >- >- // This will cause conversion nodes to be inserted later. >- fixDoubleOrBooleanEdge(leftChild); >- fixDoubleOrBooleanEdge(rightChild); >- >- // We don't need to do ref'ing on the children because we're stealing them from >- // the original division. >- Node* newDivision = m_insertionSet.insertNode( >- m_indexInBlock, SpecBytecodeDouble, *node); >- newDivision->setResult(NodeResultDouble); >- >- node->setOp(DoubleAsInt32); >- node->children.initialize(Edge(newDivision, DoubleRepUse), Edge(), Edge()); >- if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags())) >- node->setArithMode(Arith::CheckOverflow); >- else >- node->setArithMode(Arith::CheckOverflowAndNegativeZero); >- break; >- } >- fixDoubleOrBooleanEdge(leftChild); >- fixDoubleOrBooleanEdge(rightChild); >- node->setResult(NodeResultDouble); >+ node->setOp(ArithDiv); >+ node->setResult(NodeResultNumber); >+ fixupArithDiv(node, leftChild, rightChild); >+ break; >+ >+ } >+ >+ case ArithDiv: >+ case ArithMod: { >+ Edge& leftChild = node->child1(); >+ Edge& rightChild = node->child2(); >+ >+ fixupArithDiv(node, leftChild, rightChild); > break; > } > >diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h >index 5aa83a98404eaea47315aed7013d4739bbe774a7..d3f73a8c284dbd703f22e6ffceea0986f37349b2 100644 >--- a/Source/JavaScriptCore/dfg/DFGNode.h >+++ b/Source/JavaScriptCore/dfg/DFGNode.h >@@ -1129,8 +1129,7 @@ public: > NodeFlags arithNodeFlags() > { > NodeFlags result = m_flags & NodeArithFlagsMask; >- if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc || op() == DoubleAsInt32 || op() == ValueNegate >- || op() == ValueMul) >+ if (op() == ArithMul || op() == ArithDiv || op() == ValueDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == ArithFloor || op() == ArithCeil || op() == ArithTrunc || op() == DoubleAsInt32 || op() == ValueNegate || op() == ValueMul || op() == ValueDiv) > return result; > return result & ~NodeBytecodeNeedsNegZero; > } >diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h >index 40f62645769f191f17bf6bfe1b831b1cabf77b19..7d15a168913a0bad4d4ef56619fe35ecc91babc2 100644 >--- a/Source/JavaScriptCore/dfg/DFGNodeType.h >+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h >@@ -175,6 +175,7 @@ namespace JSC { namespace DFG { > \ > macro(ValueSub, NodeResultJS | NodeMustGenerate) \ > macro(ValueMul, NodeResultJS | NodeMustGenerate) \ >+ macro(ValueDiv, NodeResultJS | NodeMustGenerate) \ > \ > /* Add of values that always convers its inputs to strings. May have two or three kids. */\ > macro(StrCat, NodeResultJS | NodeMustGenerate) \ >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp >index be992af6f638f396687b22f84d6aa30f09fbd818..5dff5fbc85f4f9efb760d6befeacbbc911143df9 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp >+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp >@@ -1323,6 +1323,17 @@ JSCell* JIT_OPERATION operationSubBigInt(ExecState* exec, JSCell* op1, JSCell* o > } > > JSCell* JIT_OPERATION operationMulBigInt(ExecState* exec, JSCell* op1, JSCell* op2) >+{ >+ VM* vm = &exec->vm(); >+ NativeCallFrameTracer tracer(vm, exec); >+ >+ JSBigInt* leftOperand = jsCast<JSBigInt*>(op1); >+ JSBigInt* rightOperand = jsCast<JSBigInt*>(op2); >+ >+ return JSBigInt::multiply(exec, leftOperand, rightOperand); >+} >+ >+JSCell* JIT_OPERATION operationDivBigInt(ExecState* exec, JSCell* op1, JSCell* op2) > { > VM* vm = &exec->vm(); > NativeCallFrameTracer tracer(vm, exec); >@@ -1330,7 +1341,7 @@ JSCell* JIT_OPERATION operationMulBigInt(ExecState* exec, JSCell* op1, JSCell* o > JSBigInt* leftOperand = jsCast<JSBigInt*>(op1); > JSBigInt* rightOperand = jsCast<JSBigInt*>(op2); > >- return JSBigInt::multiply(exec, leftOperand, rightOperand); >+ return JSBigInt::divide(exec, leftOperand, rightOperand); > } > > JSCell* JIT_OPERATION operationBitAndBigInt(ExecState* exec, JSCell* op1, JSCell* op2) >diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h >index e455609a1f599eceea0186b3f6dbeb1a618bef41..4480f52ded5868f189a6a2be6c2e18bdd86ea387 100644 >--- a/Source/JavaScriptCore/dfg/DFGOperations.h >+++ b/Source/JavaScriptCore/dfg/DFGOperations.h >@@ -166,6 +166,7 @@ size_t JIT_OPERATION operationRegExpTestGeneric(ExecState*, JSGlobalObject*, Enc > size_t JIT_OPERATION operationCompareStrictEqCell(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationSubBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > 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 operationBitOrBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; > JSCell* JIT_OPERATION operationAddBigInt(ExecState*, JSCell* op1, JSCell* op2) WTF_INTERNAL; >diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >index e8299eb873c5061abb4a45f0dc1b17d239025a30..a934c2c2b00b2b3da104ea82bd7d7078c9a9c356 100644 >--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >@@ -355,6 +355,7 @@ private: > break; > } > >+ case ValueDiv: > case ArithDiv: > case ArithMod: { > SpeculatedType left = node->child1()->prediction(); >@@ -367,8 +368,13 @@ private: > changed |= mergePrediction(SpecInt32Only); > else > changed |= mergePrediction(SpecBytecodeDouble); >- } else >+ } else if (isBigIntSpeculation(left) && isBigIntSpeculation(right)) >+ changed |= mergePrediction(SpecBigInt); >+ else { > changed |= mergePrediction(SpecInt32Only | SpecBytecodeDouble); >+ if (node->mayHaveBigIntResult()) >+ changed |= mergePrediction(SpecBigInt); >+ } > } > break; > } >@@ -600,6 +606,7 @@ private: > case ArithMin: > case ArithMax: > case ArithMod: >+ case ValueDiv: > case ArithDiv: { > SpeculatedType left = node->child1()->prediction(); > SpeculatedType right = node->child2()->prediction(); >@@ -1109,6 +1116,7 @@ private: > case ValueAdd: > case ValueSub: > case ValueMul: >+ case ValueDiv: > case ArithAdd: > case ArithSub: > case ArithNegate: >diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >index 07cf01f38eb6ef13a3a2c4d06f85e5d73aa804a0..e6c58aadedf851351d6274bcfc67f984b66c2955 100644 >--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h >@@ -234,6 +234,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node, bool igno > case ValueAdd: > case ValueSub: > case ValueMul: >+ case ValueDiv: > case TryGetById: > case DeleteById: > case DeleteByVal: >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >index 465bf3fb0fd87c4a08e5f5d96fa98f3338a4ab62..491b9dee452ffdbeeb60ae0524b33585528871ca 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >@@ -4980,6 +4980,131 @@ void SpeculativeJIT::compileArithMul(Node* node) > } > } > >+void SpeculativeJIT::compileValueDiv(Node* node) >+{ >+ Edge& leftChild = node->child1(); >+ Edge& rightChild = node->child2(); >+ >+ if (leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse) { >+ SpeculateCellOperand left(this, leftChild); >+ SpeculateCellOperand right(this, rightChild); >+ GPRReg leftGPR = left.gpr(); >+ GPRReg rightGPR = right.gpr(); >+ >+ speculateBigInt(leftChild, leftGPR); >+ speculateBigInt(rightChild, rightGPR); >+ >+ flushRegisters(); >+ GPRFlushedCallResult result(this); >+ GPRReg resultGPR = result.gpr(); >+ >+ callOperation(operationDivBigInt, resultGPR, leftGPR, rightGPR); >+ >+ m_jit.exceptionCheck(); >+ cellResult(resultGPR, node); >+ return; >+ } >+ >+ if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) { >+ JSValueOperand left(this, leftChild); >+ JSValueOperand right(this, rightChild); >+ JSValueRegs leftRegs = left.jsValueRegs(); >+ JSValueRegs rightRegs = right.jsValueRegs(); >+ >+ flushRegisters(); >+ JSValueRegsFlushedCallResult result(this); >+ JSValueRegs resultRegs = result.regs(); >+ callOperation(operationValueDiv, resultRegs, leftRegs, rightRegs); >+ m_jit.exceptionCheck(); >+ >+ jsValueResult(resultRegs, node); >+ return; >+ } >+ >+ std::optional<JSValueOperand> left; >+ std::optional<JSValueOperand> right; >+ >+ JSValueRegs leftRegs; >+ JSValueRegs rightRegs; >+ >+ FPRTemporary leftNumber(this); >+ FPRTemporary rightNumber(this); >+ FPRReg leftFPR = leftNumber.fpr(); >+ FPRReg rightFPR = rightNumber.fpr(); >+ FPRTemporary fprScratch(this); >+ FPRReg scratchFPR = fprScratch.fpr(); >+ >+#if USE(JSVALUE64) >+ GPRTemporary result(this); >+ JSValueRegs resultRegs = JSValueRegs(result.gpr()); >+ GPRTemporary scratch(this); >+ GPRReg scratchGPR = scratch.gpr(); >+#else >+ GPRTemporary resultTag(this); >+ GPRTemporary resultPayload(this); >+ JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr()); >+ GPRReg scratchGPR = resultTag.gpr(); >+#endif >+ >+ SnippetOperand leftOperand(m_state.forNode(leftChild).resultType()); >+ SnippetOperand rightOperand(m_state.forNode(rightChild).resultType()); >+ >+ if (leftChild->isInt32Constant()) >+ leftOperand.setConstInt32(leftChild->asInt32()); >+#if USE(JSVALUE64) >+ else if (leftChild->isDoubleConstant()) >+ leftOperand.setConstDouble(leftChild->asNumber()); >+#endif >+ >+ if (leftOperand.isConst()) { >+ // The snippet generator only supports 1 argument as a constant. >+ // Ignore the rightChild's const-ness. >+ } else if (rightChild->isInt32Constant()) >+ rightOperand.setConstInt32(rightChild->asInt32()); >+#if USE(JSVALUE64) >+ else if (rightChild->isDoubleConstant()) >+ rightOperand.setConstDouble(rightChild->asNumber()); >+#endif >+ >+ RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst()); >+ >+ if (!leftOperand.isConst()) { >+ left.emplace(this, leftChild); >+ leftRegs = left->jsValueRegs(); >+ } >+ if (!rightOperand.isConst()) { >+ right.emplace(this, rightChild); >+ rightRegs = right->jsValueRegs(); >+ } >+ >+ JITDivGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs, >+ leftFPR, rightFPR, scratchGPR, scratchFPR); >+ gen.generateFastPath(m_jit); >+ >+ ASSERT(gen.didEmitFastPath()); >+ gen.endJumpList().append(m_jit.jump()); >+ >+ gen.slowPathJumpList().link(&m_jit); >+ silentSpillAllRegisters(resultRegs); >+ >+ if (leftOperand.isConst()) { >+ leftRegs = resultRegs; >+ m_jit.moveValue(leftChild->asJSValue(), leftRegs); >+ } >+ if (rightOperand.isConst()) { >+ rightRegs = resultRegs; >+ m_jit.moveValue(rightChild->asJSValue(), rightRegs); >+ } >+ >+ callOperation(operationValueDiv, resultRegs, leftRegs, rightRegs); >+ >+ silentFillAllRegisters(); >+ m_jit.exceptionCheck(); >+ >+ gen.endJumpList().link(&m_jit); >+ jsValueResult(resultRegs, node); >+} >+ > void SpeculativeJIT::compileArithDiv(Node* node) > { > switch (node->binaryUseKind()) { >@@ -5114,111 +5239,6 @@ void SpeculativeJIT::compileArithDiv(Node* node) > break; > } > >- case UntypedUse: { >- Edge& leftChild = node->child1(); >- Edge& rightChild = node->child2(); >- >- if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) { >- JSValueOperand left(this, leftChild); >- JSValueOperand right(this, rightChild); >- JSValueRegs leftRegs = left.jsValueRegs(); >- JSValueRegs rightRegs = right.jsValueRegs(); >- >- flushRegisters(); >- JSValueRegsFlushedCallResult result(this); >- JSValueRegs resultRegs = result.regs(); >- callOperation(operationValueDiv, resultRegs, leftRegs, rightRegs); >- m_jit.exceptionCheck(); >- >- jsValueResult(resultRegs, node); >- return; >- } >- >- std::optional<JSValueOperand> left; >- std::optional<JSValueOperand> right; >- >- JSValueRegs leftRegs; >- JSValueRegs rightRegs; >- >- FPRTemporary leftNumber(this); >- FPRTemporary rightNumber(this); >- FPRReg leftFPR = leftNumber.fpr(); >- FPRReg rightFPR = rightNumber.fpr(); >- FPRTemporary fprScratch(this); >- FPRReg scratchFPR = fprScratch.fpr(); >- >-#if USE(JSVALUE64) >- GPRTemporary result(this); >- JSValueRegs resultRegs = JSValueRegs(result.gpr()); >- GPRTemporary scratch(this); >- GPRReg scratchGPR = scratch.gpr(); >-#else >- GPRTemporary resultTag(this); >- GPRTemporary resultPayload(this); >- JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr()); >- GPRReg scratchGPR = resultTag.gpr(); >-#endif >- >- SnippetOperand leftOperand(m_state.forNode(leftChild).resultType()); >- SnippetOperand rightOperand(m_state.forNode(rightChild).resultType()); >- >- if (leftChild->isInt32Constant()) >- leftOperand.setConstInt32(leftChild->asInt32()); >-#if USE(JSVALUE64) >- else if (leftChild->isDoubleConstant()) >- leftOperand.setConstDouble(leftChild->asNumber()); >-#endif >- >- if (leftOperand.isConst()) { >- // The snippet generator only supports 1 argument as a constant. >- // Ignore the rightChild's const-ness. >- } else if (rightChild->isInt32Constant()) >- rightOperand.setConstInt32(rightChild->asInt32()); >-#if USE(JSVALUE64) >- else if (rightChild->isDoubleConstant()) >- rightOperand.setConstDouble(rightChild->asNumber()); >-#endif >- >- RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst()); >- >- if (!leftOperand.isConst()) { >- left.emplace(this, leftChild); >- leftRegs = left->jsValueRegs(); >- } >- if (!rightOperand.isConst()) { >- right.emplace(this, rightChild); >- rightRegs = right->jsValueRegs(); >- } >- >- JITDivGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs, >- leftFPR, rightFPR, scratchGPR, scratchFPR); >- gen.generateFastPath(m_jit); >- >- ASSERT(gen.didEmitFastPath()); >- gen.endJumpList().append(m_jit.jump()); >- >- gen.slowPathJumpList().link(&m_jit); >- silentSpillAllRegisters(resultRegs); >- >- if (leftOperand.isConst()) { >- leftRegs = resultRegs; >- m_jit.moveValue(leftChild->asJSValue(), leftRegs); >- } >- if (rightOperand.isConst()) { >- rightRegs = resultRegs; >- m_jit.moveValue(rightChild->asJSValue(), rightRegs); >- } >- >- callOperation(operationValueDiv, resultRegs, leftRegs, rightRegs); >- >- silentFillAllRegisters(); >- m_jit.exceptionCheck(); >- >- gen.endJumpList().link(&m_jit); >- jsValueResult(resultRegs, node); >- return; >- } >- > default: > RELEASE_ASSERT_NOT_REACHED(); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >index a20e39a83afe8cbb2929271d3ce25afe33e7ea87..fb197bafb1a73bff89d8f3d1fcfc17ec83c8f71a 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >@@ -1356,6 +1356,7 @@ public: > void compileArithNegate(Node*); > void compileValueMul(Node*); > void compileArithMul(Node*); >+ void compileValueDiv(Node*); > void compileArithDiv(Node*); > void compileArithFRound(Node*); > void compileArithMod(Node*); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >index bcf7c72488e87650af6bcf42ab57fcc17325893b..23bfe96e97fbe180a4689643658ad55c11908845 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >@@ -2070,6 +2070,11 @@ void SpeculativeJIT::compile(Node* node) > case ValueMul: > compileValueMul(node); > break; >+ >+ case ValueDiv: { >+ compileValueDiv(node); >+ break; >+ } > > case ArithDiv: { > compileArithDiv(node); >diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >index 066274490093fec2b0f2f886372adc041d058782..e8f3ea4db09e24bd1427bdf9fa61ed05dc1d0d33 100644 >--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >@@ -2213,6 +2213,11 @@ void SpeculativeJIT::compile(Node* node) > compileValueMul(node); > break; > >+ case ValueDiv: { >+ compileValueDiv(node); >+ break; >+ } >+ > case ArithDiv: { > compileArithDiv(node); > break; >diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp >index 6677ee54baf9ec75f660e0fd963eac1bc35c67c7..abd1ab2f512c35677cad4f4c95fdd5fb94ec15ce 100644 >--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp >+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp >@@ -256,6 +256,7 @@ public: > case ValueAdd: > case ValueSub: > case ValueMul: >+ case ValueDiv: > case ArithAdd: > case ArithSub: > case ArithMul: >diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >index 0a3569fe8876545768bc6c6e688ad1bc448a6af5..8dcd4223b57b6470a8c7b3bca082732559821aa9 100644 >--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp >@@ -94,6 +94,7 @@ inline CapabilityLevel canCompile(Node* node) > case ValueAdd: > case ValueSub: > case ValueMul: >+ case ValueDiv: > case StrCat: > case ArithAdd: > case ArithClz32: >diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >index 0823fc8f78058daf34b59081d73cc7af3173ba9c..9061ae104a369bb6a8aae78a079d8d3e1c40019d 100644 >--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >@@ -613,6 +613,9 @@ private: > case ArithMul: > compileArithMul(); > break; >+ case ValueDiv: >+ compileValueDiv(); >+ break; > case ArithDiv: > compileArithDiv(); > break; >@@ -1875,7 +1878,7 @@ private: > LValue left = lowBigInt(m_node->child1()); > LValue right = lowBigInt(m_node->child2()); > >- LValue result = vmCall(pointerType(), m_out.operation(operationAddBigInt), m_callFrame, left, right); >+ LValue result = vmCall(Int64, m_out.operation(operationAddBigInt), m_callFrame, left, right); > setJSValue(result); > return; > } >@@ -1894,7 +1897,7 @@ private: > LValue left = lowBigInt(m_node->child1()); > LValue right = lowBigInt(m_node->child2()); > >- LValue result = vmCall(pointerType(), m_out.operation(operationSubBigInt), m_callFrame, left, right); >+ LValue result = vmCall(Int64, m_out.operation(operationSubBigInt), m_callFrame, left, right); > setJSValue(result); > return; > } >@@ -2280,6 +2283,20 @@ private: > } > } > >+ void compileValueDiv() >+ { >+ if (m_node->isBinaryUseKind(BigIntUse)) { >+ LValue left = lowBigInt(m_node->child1()); >+ LValue right = lowBigInt(m_node->child2()); >+ >+ LValue result = vmCall(Int64, m_out.operation(operationDivBigInt), m_callFrame, left, right); >+ setJSValue(result); >+ return; >+ } >+ >+ emitBinarySnippet<JITDivGenerator, NeedScratchFPR>(operationValueDiv); >+ } >+ > void compileArithDiv() > { > switch (m_node->binaryUseKind()) { >@@ -2338,11 +2355,6 @@ private: > break; > } > >- case UntypedUse: { >- emitBinarySnippet<JITDivGenerator, NeedScratchFPR>(operationValueDiv); >- break; >- } >- > default: > DFG_CRASH(m_graph, m_node, "Bad use kind"); > break; >@@ -2867,7 +2879,7 @@ private: > { > if (m_node->child1().useKind() == UntypedUse) { > LValue operand = lowJSValue(m_node->child1()); >- LValue result = vmCall(pointerType(), m_out.operation(operationValueBitNot), m_callFrame, operand); >+ LValue result = vmCall(Int64, m_out.operation(operationValueBitNot), m_callFrame, operand); > setJSValue(result); > return; > } >@@ -2881,7 +2893,7 @@ private: > LValue left = lowBigInt(m_node->child1()); > LValue right = lowBigInt(m_node->child2()); > >- LValue result = vmCall(pointerType(), m_out.operation(operationBitAndBigInt), m_callFrame, left, right); >+ LValue result = vmCall(Int64, m_out.operation(operationBitAndBigInt), m_callFrame, left, right); > setJSValue(result); > return; > } >@@ -2900,7 +2912,7 @@ private: > LValue left = lowBigInt(m_node->child1()); > LValue right = lowBigInt(m_node->child2()); > >- LValue result = vmCall(pointerType(), m_out.operation(operationBitOrBigInt), m_callFrame, left, right); >+ LValue result = vmCall(Int64, m_out.operation(operationBitOrBigInt), m_callFrame, left, right); > setJSValue(result); > return; > } >@@ -2919,7 +2931,7 @@ private: > LValue left = lowBigInt(m_node->child1()); > LValue right = lowBigInt(m_node->child2()); > >- LValue result = vmCall(pointerType(), m_out.operation(operationBitXorBigInt), m_callFrame, left, right); >+ LValue result = vmCall(Int64, m_out.operation(operationBitXorBigInt), m_callFrame, left, right); > setJSValue(result); > return; > } >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index caa0a568b3c4c1044ddd90d5fc1168a932f56482..babf26a6441e0871688dc691cad60a1d8935e0fd 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,14 @@ >+2018-12-12 Caio Lima <ticaiolima@gmail.com> >+ >+ [BigInt] Add ValueDiv into DFG >+ https://bugs.webkit.org/show_bug.cgi?id=186178 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * stress/big-int-div-jit-osr.js: Added. >+ * stress/big-int-div-jit-untyped.js: Added. >+ * stress/value-div-fixup-int32-big-int.js: Added. >+ > 2018-12-10 Caio Lima <ticaiolima@gmail.com> > > [BigInt] Add ValueMul into DFG >diff --git a/JSTests/stress/big-int-div-jit-osr.js b/JSTests/stress/big-int-div-jit-osr.js >new file mode 100644 >index 0000000000000000000000000000000000000000..bd6ab97dc02714b1fe84b1477462b30e0232e88f >--- /dev/null >+++ b/JSTests/stress/big-int-div-jit-osr.js >@@ -0,0 +1,25 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntDiv(x, y) { >+ return x / y; >+} >+noInline(bigIntDiv); >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntDiv(30n, 10n); >+ assert.sameValue(r, 3n, 30n + " / " + 10n + " = " + r); >+} >+ >+let r = bigIntDiv(30, 10); >+assert.sameValue(r, 3, 3 + " / " + 10 + " = " + r); >+ >+r = bigIntDiv("30", "10"); >+assert.sameValue(r, 3, 30 + " * " + 10 + " = " + r); >+ >diff --git a/JSTests/stress/big-int-div-jit-untyped.js b/JSTests/stress/big-int-div-jit-untyped.js >new file mode 100644 >index 0000000000000000000000000000000000000000..5e9a377f3871b9913e979ba6948ec9c2b84a74fa >--- /dev/null >+++ b/JSTests/stress/big-int-div-jit-untyped.js >@@ -0,0 +1,36 @@ >+//@ runBigIntEnabled >+ >+let assert = { >+ sameValue: function(i, e, m) { >+ if (i !== e) >+ throw new Error(m); >+ } >+} >+ >+function bigIntDiv(x, y) { >+ return x / y; >+} >+noInline(bigIntDiv); >+ >+let o = {valueOf: () => 10n}; >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntDiv(30n, o); >+ assert.sameValue(r, 3n, 30n + " / {valueOf: () => 10n} = " + r); >+} >+ >+o2 = {valueOf: () => 10000n}; >+ >+for (let i = 0; i < 10000; i++) { >+ let r = bigIntDiv(o2, o); >+ assert.sameValue(r, 1000n, "{valueOf: () => 10000n} / {valueOf: () => 10n} = " + r); >+} >+ >+o = Object(10n); >+let r = bigIntDiv(30n, o); >+assert.sameValue(r, 3n, 30n + " / Object(10n) = " + r); >+ >+o2 = Object(3240n); >+r = bigIntDiv(o2, o); >+assert.sameValue(r, 324n, "Object(3240n) / Object(10n) = " + r); >+ >diff --git a/JSTests/stress/value-div-fixup-int32-big-int.js b/JSTests/stress/value-div-fixup-int32-big-int.js >new file mode 100644 >index 0000000000000000000000000000000000000000..f6fdaf6f23fc4a73c3080ae4b1c8f440974594a8 >--- /dev/null >+++ b/JSTests/stress/value-div-fixup-int32-big-int.js >@@ -0,0 +1,29 @@ >+//@ runBigIntEnabled >+ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Bad!"); >+} >+ >+function foo() { >+ let c; >+ do { >+ >+ let a = 2; >+ let b = 3n; >+ for (let i = 0; i < 10000; i++) { >+ c = i; >+ } >+ >+ c = a / b; >+ } while(true); >+ >+ return c; >+} >+ >+try { >+ foo(); >+} catch(e) { >+ assert(e instanceof TypeError, true); >+} >+ >diff --git a/PerformanceTests/BigIntBench/big-int-simple-div.js b/PerformanceTests/BigIntBench/big-int-simple-div.js >new file mode 100644 >index 0000000000000000000000000000000000000000..990539d63b32773b10553d93d4ec3fc291c96de3 >--- /dev/null >+++ b/PerformanceTests/BigIntBench/big-int-simple-div.js >@@ -0,0 +1,15 @@ >+function bigInt(a, b) { >+ let c = a / b; >+ return a + c / b; >+} >+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 3b3186bc1e2d07cd66ba1c38936f16ec80a62e55..93c8e1c5e0a10ddf82159e5381aa563b11ab00bc 100644 >--- a/PerformanceTests/ChangeLog >+++ b/PerformanceTests/ChangeLog >@@ -1,3 +1,13 @@ >+2018-12-12 Caio Lima <ticaiolima@gmail.com> >+ >+ [BigInt] Add ValueDiv into DFG >+ https://bugs.webkit.org/show_bug.cgi?id=186178 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * BigIntBench/big-int-simple-div.js: Added. >+ (bigInt): >+ > 2018-12-10 Caio Lima <ticaiolima@gmail.com> > > [BigInt] Add ValueMul into DFG
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 186178
:
356320
|
357118
|
357119
|
357128
|
357171