Diff
Modified: trunk/JSTests/ChangeLog (260729 => 260730)
--- trunk/JSTests/ChangeLog 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/JSTests/ChangeLog 2020-04-26 21:11:50 UTC (rev 260730)
@@ -1,3 +1,31 @@
+2020-04-26 Yusuke Suzuki <ysuz...@apple.com>
+
+ [JSC] ValueAdd, VaueSub, ValueMul, Inc, Dec should say SpecBigInt32 prediction based on ArithProfile
+ https://bugs.webkit.org/show_bug.cgi?id=211038
+
+ Reviewed by Filip Pizlo.
+
+ * stress/bigint32-add-overflow.js: Added.
+ (shouldBe):
+ (add):
+ (noInline):
+ * stress/bigint32-dec-overflow.js: Added.
+ (shouldBe):
+ (dec):
+ (noInline):
+ * stress/bigint32-inc-overflow.js: Added.
+ (shouldBe):
+ (inc):
+ (noInline):
+ * stress/bigint32-mul-overflow.js: Added.
+ (shouldBe):
+ (mul):
+ (noInline):
+ * stress/bigint32-sub-overflow.js: Added.
+ (shouldBe):
+ (sub):
+ (noInline):
+
2020-04-25 Yusuke Suzuki <ysuz...@apple.com>
[JSC] Handle BigInt32 INT32_MIN shift amount
Added: trunk/JSTests/stress/bigint32-add-overflow.js (0 => 260730)
--- trunk/JSTests/stress/bigint32-add-overflow.js (rev 0)
+++ trunk/JSTests/stress/bigint32-add-overflow.js 2020-04-26 21:11:50 UTC (rev 260730)
@@ -0,0 +1,20 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function add(a, b) {
+ return a + b;
+}
+noInline(add);
+
+{
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(add(BigInt(i), 2n), BigInt(i + 2));
+}
+{
+ let max = 0x7fffffffn;
+ let result = 0x80000001n;
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(add(max, 2n), result);
+}
Added: trunk/JSTests/stress/bigint32-dec-overflow.js (0 => 260730)
--- trunk/JSTests/stress/bigint32-dec-overflow.js (rev 0)
+++ trunk/JSTests/stress/bigint32-dec-overflow.js 2020-04-26 21:11:50 UTC (rev 260730)
@@ -0,0 +1,20 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function dec(a) {
+ return --a;
+}
+noInline(dec);
+
+{
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(dec(BigInt(i)), BigInt(i - 1));
+}
+{
+ let min = -0x7fffffffn - 1n;
+ let result = -0x80000001n;
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(dec(min), result);
+}
Added: trunk/JSTests/stress/bigint32-inc-overflow.js (0 => 260730)
--- trunk/JSTests/stress/bigint32-inc-overflow.js (rev 0)
+++ trunk/JSTests/stress/bigint32-inc-overflow.js 2020-04-26 21:11:50 UTC (rev 260730)
@@ -0,0 +1,20 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function inc(a) {
+ return ++a;
+}
+noInline(inc);
+
+{
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(inc(BigInt(i)), BigInt(i + 1));
+}
+{
+ let max = 0x7fffffffn;
+ let result = 0x80000000n;
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(inc(max), result);
+}
Added: trunk/JSTests/stress/bigint32-mul-overflow.js (0 => 260730)
--- trunk/JSTests/stress/bigint32-mul-overflow.js (rev 0)
+++ trunk/JSTests/stress/bigint32-mul-overflow.js 2020-04-26 21:11:50 UTC (rev 260730)
@@ -0,0 +1,20 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function mul(a, b) {
+ return a * b;
+}
+noInline(mul);
+
+{
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(mul(BigInt(i), 2n), BigInt(i * 2));
+}
+{
+ let max = 0x7fffffffn;
+ let result = 0xfffffffen;
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(mul(max, 2n), result);
+}
Added: trunk/JSTests/stress/bigint32-sub-overflow.js (0 => 260730)
--- trunk/JSTests/stress/bigint32-sub-overflow.js (rev 0)
+++ trunk/JSTests/stress/bigint32-sub-overflow.js 2020-04-26 21:11:50 UTC (rev 260730)
@@ -0,0 +1,20 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function sub(a, b) {
+ return a - b;
+}
+noInline(sub);
+
+{
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(sub(BigInt(i), 2n), BigInt(i - 2));
+}
+{
+ let min = -0x7fffffffn - 1n;
+ let result = -0x80000002n;
+ for (var i = 0; i < 100000; ++i)
+ shouldBe(sub(min, 2n), result);
+}
Modified: trunk/Source/_javascript_Core/ChangeLog (260729 => 260730)
--- trunk/Source/_javascript_Core/ChangeLog 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-04-26 21:11:50 UTC (rev 260730)
@@ -1,3 +1,77 @@
+2020-04-26 Yusuke Suzuki <ysuz...@apple.com>
+
+ [JSC] ValueAdd, VaueSub, ValueMul, Inc, Dec should say SpecBigInt32 prediction based on ArithProfile
+ https://bugs.webkit.org/show_bug.cgi?id=211038
+
+ Reviewed by Filip Pizlo.
+
+ This patch adds profile feedback to ValueAdd, ValueSub, ValueMul, Inc, Dec to say SpecBigInt32 prediction.
+
+ Our HeapBigInt v.s. BigInt32 strategy is simpler than Double v.s. Int32 strategy: we always
+ prefer BigInt32 over HeapBigInt. This is because HeapBigInt calculation and conversion require
+ much higher cost than BigInt32. This tradeoff is largely different from Double v.s. Int32.
+ So keeping HeapBigInt is simply inefficient when we can use BigInt32.
+
+ This means that ArithProfile's feedback is also very simple. If we see HeapBigInt, this means
+ overflow happens. In DFG, we propagate this information to ValueAdd, ValueSub, and ValueMul nodes
+ and record it in DFGNodeFlags. And based on this information, we change the prediction and
+ speculation in prediction propagation and fixup phase.
+
+ We change exit reason from Overflow to BigInt32Overflow since Overflow is solely used for Int32 case,
+ and we have Int52Overflow for Int52 case. We should have BigInt32Overflow for BigInt32 to precisely
+ record and tell about what happens in DFG as a feedback for the next compilation.
+
+ We add BigInt32 speculation for ValueSub. Previously, we missed that in fixup phase and we always
+ speculate ValueSub with AnyBigIntUse or HeapBigIntUse. Now it can use BigInt32Use.
+
+ We also fix Inc / Dec's fixup phase to use BigInt path. Previously, it was always using UntypedUse since
+ `node->child1()->shouldSpeculateUntypedForArithmetic()` returns true for BigInt. We fix the ordering of
+ speculation attempts as it is done in the other places in fixup phase.
+
+ This patch offers 7.9% performance improvement in sunspider-sha1-big-int.
+
+ ToT Patched
+
+ sunspider-sha1-big-int 134.5668+-2.8695 ^ 124.6743+-0.7541 ^ definitely 1.0793x faster
+
+ * bytecode/ExitKind.cpp:
+ (JSC::exitKindToString):
+ * bytecode/ExitKind.h:
+ * bytecode/SpeculatedType.h:
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::makeSafe):
+ (JSC::DFG::ByteCodeParser::makeDivSafe):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::binaryArithShouldSpeculateBigInt32):
+ (JSC::DFG::Graph::unaryArithShouldSpeculateBigInt32):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::mayHaveBigInt32Result):
+ (JSC::DFG::Node::mayHaveHeapBigIntResult):
+ (JSC::DFG::Node::mayHaveBigIntResult):
+ (JSC::DFG::Node::canSpeculateBigInt32):
+ (JSC::DFG::Node::canSpeculateInt52):
+ * dfg/DFGNodeFlags.cpp:
+ (JSC::DFG::dumpNodeFlags):
+ * dfg/DFGNodeFlags.h:
+ (JSC::DFG::nodeMayHaveHeapBigInt):
+ (JSC::DFG::nodeCanSpeculateBigInt32):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileValueAdd):
+ (JSC::DFG::SpeculativeJIT::compileValueSub):
+ (JSC::DFG::SpeculativeJIT::compileValueMul):
+ (JSC::DFG::SpeculativeJIT::compileValueDiv):
+ (JSC::DFG::SpeculativeJIT::speculateHeapBigInt):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileValueAdd):
+ (JSC::FTL::DFG::LowerDFGToB3::compileValueSub):
+ (JSC::FTL::DFG::LowerDFGToB3::compileValueMul):
+ (JSC::FTL::DFG::LowerDFGToB3::compileValueDiv):
+
2020-04-25 Ross Kirsling <ross.kirsl...@sony.com>
[JSC] isCallable is redundant with isFunction
Modified: trunk/Source/_javascript_Core/bytecode/ExitKind.cpp (260729 => 260730)
--- trunk/Source/_javascript_Core/bytecode/ExitKind.cpp 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/bytecode/ExitKind.cpp 2020-04-26 21:11:50 UTC (rev 260730)
@@ -88,6 +88,8 @@
return "ExceptionCheck";
case GenericUnwind:
return "GenericUnwind";
+ case BigInt32Overflow:
+ return "BigInt32Overflow";
}
RELEASE_ASSERT_NOT_REACHED();
return "Unknown";
Modified: trunk/Source/_javascript_Core/bytecode/ExitKind.h (260729 => 260730)
--- trunk/Source/_javascript_Core/bytecode/ExitKind.h 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/bytecode/ExitKind.h 2020-04-26 21:11:50 UTC (rev 260730)
@@ -55,6 +55,7 @@
DebuggerEvent, // We exited because we need to service the debugger.
ExceptionCheck, // We exited because a direct exception check showed that we threw an exception from a C call.
GenericUnwind, // We exited because we arrived at this OSR exit from genericUnwind.
+ BigInt32Overflow, // We exited because of an BigInt32 overflow.
};
const char* exitKindToString(ExitKind);
Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.h (260729 => 260730)
--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.h 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.h 2020-04-26 21:11:50 UTC (rev 260730)
@@ -100,7 +100,12 @@
static constexpr SpeculatedType SpecEmpty = 1ull << 40; // It's definitely an empty value marker.
static constexpr SpeculatedType SpecHeapBigInt = 1ull << 41; // It's definitely a BigInt that is allocated on the heap
static constexpr SpeculatedType SpecBigInt32 = 1ull << 42; // It's definitely a small BigInt that is inline the JSValue
+#if USE(BIGINT32)
static constexpr SpeculatedType SpecBigInt = SpecBigInt32 | SpecHeapBigInt;
+#else
+// We should not include SpecBigInt32. We are using SpecBigInt in various places like prediction. If this includes SpecBigInt32, fixup phase is confused if !USE(BIGINT32) since it is not using AnyBigIntUse.
+static constexpr SpeculatedType SpecBigInt = SpecHeapBigInt;
+#endif
static constexpr SpeculatedType SpecDataViewObject = 1ull << 43; // It's definitely a JSDataView.
static constexpr SpeculatedType SpecPrimitive = SpecString | SpecSymbol | SpecBytecodeNumber | SpecMisc | SpecBigInt; // It's any non-Object JSValue.
static constexpr SpeculatedType SpecObject = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecDateObject | SpecPromiseObject | SpecMapObject | SpecSetObject | SpecWeakMapObject | SpecWeakSetObject | SpecProxyObject | SpecDerivedArray | SpecObjectOther | SpecDataViewObject; // Bitmask used for testing for any kind of object prediction.
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (260729 => 260730)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h 2020-04-26 21:11:50 UTC (rev 260730)
@@ -766,8 +766,10 @@
// the format of our result:
// https://bugs.webkit.org/show_bug.cgi?id=210982
setTypeForNode(node, SpecBigInt);
- } else if (node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use)
+ } else if (node->isBinaryUseKind(AnyBigIntUse))
setTypeForNode(node, SpecBigInt);
+ else if (node->isBinaryUseKind(BigInt32Use))
+ setTypeForNode(node, SpecBigInt32);
else {
DFG_ASSERT(m_graph, node, node->binaryUseKind() == UntypedUse);
clobberWorld();
@@ -1056,8 +1058,10 @@
// the format of our result:
// https://bugs.webkit.org/show_bug.cgi?id=210982
setTypeForNode(node, SpecBigInt);
- } else if (node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use)
+ } else if (node->isBinaryUseKind(AnyBigIntUse))
setTypeForNode(node, SpecBigInt);
+ else if (node->isBinaryUseKind(BigInt32Use))
+ setTypeForNode(node, SpecBigInt32);
else {
clobberWorld();
setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (260729 => 260730)
--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp 2020-04-26 21:11:50 UTC (rev 260730)
@@ -1011,8 +1011,10 @@
node->mergeFlags(NodeMayHaveDoubleResult);
if (observed.didObserveNonNumeric())
node->mergeFlags(NodeMayHaveNonNumericResult);
- if (observed.didObserveBigInt())
- node->mergeFlags(NodeMayHaveBigIntResult);
+ if (observed.didObserveBigInt32())
+ node->mergeFlags(NodeMayHaveBigInt32Result);
+ if (observed.didObserveHeapBigInt() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BigInt32Overflow))
+ node->mergeFlags(NodeMayHaveHeapBigIntResult);
break;
}
case ValueMul:
@@ -1030,8 +1032,10 @@
node->mergeFlags(NodeMayHaveDoubleResult);
if (arithProfile->didObserveNonNumeric())
node->mergeFlags(NodeMayHaveNonNumericResult);
- if (arithProfile->didObserveBigInt())
- node->mergeFlags(NodeMayHaveBigIntResult);
+ if (arithProfile->didObserveBigInt32())
+ node->mergeFlags(NodeMayHaveBigInt32Result);
+ if (arithProfile->didObserveHeapBigInt() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BigInt32Overflow))
+ node->mergeFlags(NodeMayHaveHeapBigIntResult);
break;
}
case ValueNegate:
@@ -1049,8 +1053,10 @@
node->mergeFlags(NodeMayOverflowInt32InBaseline);
if (arithProfile->didObserveNonNumeric())
node->mergeFlags(NodeMayHaveNonNumericResult);
- if (arithProfile->didObserveBigInt())
- node->mergeFlags(NodeMayHaveBigIntResult);
+ if (arithProfile->didObserveBigInt32())
+ node->mergeFlags(NodeMayHaveBigInt32Result);
+ if (arithProfile->didObserveHeapBigInt() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BigInt32Overflow))
+ node->mergeFlags(NodeMayHaveHeapBigIntResult);
break;
}
@@ -1099,9 +1105,12 @@
node->mergeFlags(NodeMayOverflowInt32InBaseline | NodeMayNegZeroInBaseline);
BinaryArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->binaryArithProfileForBytecodeIndex(m_currentIndex);
- if (arithProfile->didObserveBigInt())
- node->mergeFlags(NodeMayHaveBigIntResult);
+ if (arithProfile->didObserveBigInt32())
+ node->mergeFlags(NodeMayHaveBigInt32Result);
+ if (arithProfile->didObserveHeapBigInt() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BigInt32Overflow))
+ node->mergeFlags(NodeMayHaveHeapBigIntResult);
+
return node;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (260729 => 260730)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2020-04-26 21:11:50 UTC (rev 260730)
@@ -188,6 +188,42 @@
case Inc:
case Dec: {
+ if (node->child1()->shouldSpeculateBigInt()) {
+ if (node->child1()->shouldSpeculateHeapBigInt()) {
+ // FIXME: the freezing does not appear useful (since the JSCell is kept alive by vm), but it refuses to compile otherwise.
+ // FIXME: we might optimize inc/dec to a specialized function call instead in that case.
+ node->setOp(op == Inc ? ValueAdd : ValueSub);
+ Node* nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecHeapBigInt, JSConstant, node->origin, OpInfo(m_graph.freeze(vm().heapBigIntConstantOne.get())));
+ node->children.setChild2(Edge(nodeConstantOne));
+ fixEdge<HeapBigIntUse>(node->child1());
+ fixEdge<HeapBigIntUse>(node->child2());
+ // HeapBigInts are cells, so the default of NodeResultJS is good here
+ break;
+ }
+#if USE(BIGINT32)
+ if (m_graph.unaryArithShouldSpeculateBigInt32(node, FixupPass)) {
+ node->setOp(op == Inc ? ValueAdd : ValueSub);
+ Node* nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecBigInt32, JSConstant, node->origin, OpInfo(m_graph.freeze(jsBigInt32(1))));
+ node->children.setChild2(Edge(nodeConstantOne));
+ fixEdge<BigInt32Use>(node->child1());
+ fixEdge<BigInt32Use>(node->child2());
+ // The default of NodeResultJS is good enough for now.
+ // FIXME: consider having a special representation for small BigInts instead.
+ break;
+ }
+
+ // FIXME: the freezing does not appear useful (since the JSCell is kept alive by vm), but it refuses to compile otherwise.
+ // FIXME: we might optimize inc/dec to a specialized function call instead in that case.
+ node->setOp(op == Inc ? ValueAdd : ValueSub);
+ Node* nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecBigInt32, JSConstant, node->origin, OpInfo(m_graph.freeze(jsBigInt32(1))));
+ node->children.setChild2(Edge(nodeConstantOne));
+ fixEdge<AnyBigIntUse>(node->child1());
+ fixEdge<AnyBigIntUse>(node->child2());
+ // The default of NodeResultJS is good here
+#endif // USE(BIGINT32)
+ break;
+ }
+
if (node->child1()->shouldSpeculateUntypedForArithmetic()) {
fixEdge<UntypedUse>(node->child1());
break;
@@ -202,34 +238,6 @@
fixEdge<Int32Use>(node->child1());
fixEdge<Int32Use>(node->child2());
node->setResult(NodeResultInt32);
- } else if (node->child1()->shouldSpeculateHeapBigInt()) {
- // FIXME: the freezing does not appear useful (since the JSCell is kept alive by vm), but it refuses to compile otherwise.
- // FIXME: we might optimize inc/dec to a specialized function call instead in that case.
- node->setOp(op == Inc ? ValueAdd : ValueSub);
- nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecHeapBigInt, JSConstant, node->origin, OpInfo(m_graph.freeze(vm().heapBigIntConstantOne.get())));
- node->children.setChild2(Edge(nodeConstantOne));
- fixEdge<HeapBigIntUse>(node->child1());
- fixEdge<HeapBigIntUse>(node->child2());
- // HeapBigInts are cells, so the default of NodeResultJS is good here
-#if USE(BIGINT32)
- } else if (node->child1()->shouldSpeculateBigInt32()) {
- node->setOp(op == Inc ? ValueAdd : ValueSub);
- nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecBigInt32, JSConstant, node->origin, OpInfo(m_graph.freeze(jsBigInt32(1))));
- node->children.setChild2(Edge(nodeConstantOne));
- fixEdge<BigInt32Use>(node->child1());
- fixEdge<BigInt32Use>(node->child2());
- // The default of NodeResultJS is good enough for now.
- // FIXME: consider having a special representation for small BigInts instead.
- } else if (node->child1()->shouldSpeculateBigInt()) {
- // FIXME: the freezing does not appear useful (since the JSCell is kept alive by vm), but it refuses to compile otherwise.
- // FIXME: we might optimize inc/dec to a specialized function call instead in that case.
- node->setOp(op == Inc ? ValueAdd : ValueSub);
- nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecBigInt32, JSConstant, node->origin, OpInfo(m_graph.freeze(jsBigInt32(1))));
- node->children.setChild2(Edge(nodeConstantOne));
- fixEdge<AnyBigIntUse>(node->child1());
- fixEdge<AnyBigIntUse>(node->child2());
- // The default of NodeResultJS is good here
-#endif // USE(BIGINT32)
} else if (node->child1()->shouldSpeculateInt52()) {
node->setOp(op == Inc ? ArithAdd : ArithSub);
node->setArithMode(Arith::CheckOverflow);
@@ -262,10 +270,16 @@
}
#if USE(BIGINT32)
+ if (m_graph.binaryArithShouldSpeculateBigInt32(node, FixupPass)) {
+ fixEdge<BigInt32Use>(child1);
+ fixEdge<BigInt32Use>(child2);
+ break;
+ }
+
if (Node::shouldSpeculateBigInt(child1.node(), child2.node())) {
fixEdge<AnyBigIntUse>(child1);
fixEdge<AnyBigIntUse>(child2);
- break;
+ break;
}
#endif
@@ -311,7 +325,16 @@
fixEdge<HeapBigIntUse>(node->child1());
fixEdge<HeapBigIntUse>(node->child2());
#endif
- node->clearFlags(NodeMustGenerate);
+ // Shift can throw RangeError.
+ switch (node->op()) {
+ case ValueBitXor:
+ case ValueBitOr:
+ case ValueBitAnd:
+ node->clearFlags(NodeMustGenerate);
+ break;
+ default:
+ break;
+ }
break;
}
@@ -513,7 +536,7 @@
fixEdge<HeapBigIntUse>(child1);
fixEdge<HeapBigIntUse>(child2);
#if USE(BIGINT32)
- } else if (Node::shouldSpeculateBigInt32(child1.node(), child2.node())) {
+ } else if (m_graph.binaryArithShouldSpeculateBigInt32(node, FixupPass)) {
fixEdge<BigInt32Use>(child1);
fixEdge<BigInt32Use>(child2);
} else if (Node::shouldSpeculateBigInt(child1.node(), child2.node())) {
@@ -606,7 +629,7 @@
if (Node::shouldSpeculateBigInt(leftChild.node(), rightChild.node())) {
#if USE(BIGINT32)
- if (Node::shouldSpeculateBigInt32(leftChild.node(), rightChild.node())) {
+ if (m_graph.binaryArithShouldSpeculateBigInt32(node, FixupPass)) {
fixEdge<BigInt32Use>(node->child1());
fixEdge<BigInt32Use>(node->child2());
} else if (Node::shouldSpeculateHeapBigInt(leftChild.node(), rightChild.node())) {
@@ -737,7 +760,7 @@
}
case ValuePow: {
- if (Node::shouldSpeculateHeapBigInt(node->child1().node(), node->child1().node())) {
+ if (Node::shouldSpeculateHeapBigInt(node->child1().node(), node->child2().node())) {
fixEdge<HeapBigIntUse>(node->child1());
fixEdge<HeapBigIntUse>(node->child2());
node->clearFlags(NodeMustGenerate);
Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (260729 => 260730)
--- trunk/Source/_javascript_Core/dfg/DFGGraph.h 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h 2020-04-26 21:11:50 UTC (rev 260730)
@@ -410,6 +410,26 @@
&& !hasExitSite(node, Int52Overflow);
}
+#if USE(BIGINT32)
+ bool binaryArithShouldSpeculateBigInt32(Node* node, PredictionPass pass)
+ {
+ if (!node->canSpeculateBigInt32(pass))
+ return false;
+ if (hasExitSite(node, BigInt32Overflow))
+ return false;
+ return Node::shouldSpeculateBigInt32(node->child1().node(), node->child2().node());
+ }
+
+ bool unaryArithShouldSpeculateBigInt32(Node* node, PredictionPass pass)
+ {
+ if (!node->canSpeculateBigInt32(pass))
+ return false;
+ if (hasExitSite(node, BigInt32Overflow))
+ return false;
+ return node->child1()->shouldSpeculateBigInt32();
+ }
+#endif
+
bool canOptimizeStringObjectAccess(const CodeOrigin&);
bool getRegExpPrototypeProperty(JSObject* regExpPrototype, Structure* regExpPrototypeStructure, UniquedStringImpl* uid, JSValue& returnJSValue);
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (260729 => 260730)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2020-04-26 21:11:50 UTC (rev 260730)
@@ -1202,9 +1202,19 @@
return m_flags & NodeMayHaveNonNumericResult;
}
+ bool mayHaveBigInt32Result()
+ {
+ return m_flags & NodeMayHaveBigInt32Result;
+ }
+
+ bool mayHaveHeapBigIntResult()
+ {
+ return m_flags & NodeMayHaveHeapBigIntResult;
+ }
+
bool mayHaveBigIntResult()
{
- return m_flags & NodeMayHaveBigIntResult;
+ return mayHaveBigInt32Result() || mayHaveHeapBigIntResult();
}
bool hasNewArrayBufferData()
@@ -2866,6 +2876,11 @@
{
return nodeCanSpeculateInt52(arithNodeFlags(), source);
}
+
+ bool canSpeculateBigInt32(RareCaseProfilingSource source)
+ {
+ return nodeCanSpeculateBigInt32(arithNodeFlags(), source);
+ }
RareCaseProfilingSource sourceFor(PredictionPass pass)
{
@@ -2884,6 +2899,11 @@
return canSpeculateInt52(sourceFor(pass));
}
+ bool canSpeculateBigInt32(PredictionPass pass)
+ {
+ return canSpeculateBigInt32(sourceFor(pass));
+ }
+
bool hasTypeLocation()
{
return op() == ProfileType;
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeFlags.cpp (260729 => 260730)
--- trunk/Source/_javascript_Core/dfg/DFGNodeFlags.cpp 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeFlags.cpp 2020-04-26 21:11:50 UTC (rev 260730)
@@ -88,9 +88,12 @@
if (flags & NodeMayHaveDoubleResult)
out.print(comma, "MayHaveDoubleResult");
- if (flags & NodeMayHaveBigIntResult)
- out.print(comma, "MayHaveBigIntResult");
+ if (flags & NodeMayHaveBigInt32Result)
+ out.print(comma, "MayHaveBigInt32Result");
+ if (flags & NodeMayHaveHeapBigIntResult)
+ out.print(comma, "MayHaveHeapBigIntResult");
+
if (flags & NodeMayHaveNonNumericResult)
out.print(comma, "MayHaveNonNumericResult");
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeFlags.h (260729 => 260730)
--- trunk/Source/_javascript_Core/dfg/DFGNodeFlags.h 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeFlags.h 2020-04-26 21:11:50 UTC (rev 260730)
@@ -42,11 +42,10 @@
#define NodeResultInt52 0x0005
#define NodeResultBoolean 0x0006
#define NodeResultStorage 0x0007
-
+
#define NodeMustGenerate 0x0008 // set on nodes that have side effects, and may not trivially be removed by DCE.
#define NodeHasVarArgs 0x0010
-
-#define NodeBehaviorMask 0x007e0
+
#define NodeMayHaveDoubleResult 0x00020
#define NodeMayOverflowInt52 0x00040
#define NodeMayOverflowInt32InBaseline 0x00080
@@ -53,26 +52,27 @@
#define NodeMayOverflowInt32InDFG 0x00100
#define NodeMayNegZeroInBaseline 0x00200
#define NodeMayNegZeroInDFG 0x00400
-#define NodeMayHaveNonNumericResult 0x00800
-// FIXME: we should have separate flags for HeapBigInt and BigInt32, currently prediction propagation will pessimize things.
-#define NodeMayHaveBigIntResult 0x01000
-#define NodeMayHaveNonIntResult (NodeMayHaveDoubleResult | NodeMayHaveNonNumericResult | NodeMayHaveBigIntResult)
-
-#define NodeBytecodeBackPropMask 0x3e000
-#define NodeBytecodeUseBottom 0x00000
-#define NodeBytecodeUsesAsNumber 0x02000 // The result of this computation may be used in a context that observes fractional, or bigger-than-int32, results.
-#define NodeBytecodeNeedsNegZero 0x04000 // The result of this computation may be used in a context that observes -0.
-#define NodeBytecodeUsesAsOther 0x08000 // The result of this computation may be used in a context that distinguishes between NaN and other things (like undefined).
-#define NodeBytecodeUsesAsValue (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther)
-#define NodeBytecodeUsesAsInt 0x10000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
-#define NodeBytecodeUsesAsArrayIndex 0x20000 // The result of this computation is known to be used in a context that strongly prefers integer values, to the point that we should avoid using doubles if at all possible.
+#define NodeMayHaveBigInt32Result 0x00800
+#define NodeMayHaveHeapBigIntResult 0x01000
+#define NodeMayHaveNonNumericResult 0x02000
+#define NodeBehaviorMask (NodeMayHaveDoubleResult | NodeMayOverflowInt52 | NodeMayOverflowInt32InBaseline | NodeMayOverflowInt32InDFG | NodeMayNegZeroInBaseline | NodeMayNegZeroInDFG | NodeMayHaveBigInt32Result | NodeMayHaveHeapBigIntResult | NodeMayHaveNonNumericResult)
+#define NodeMayHaveNonIntResult (NodeMayHaveDoubleResult | NodeMayHaveNonNumericResult | NodeMayHaveBigInt32Result | NodeMayHaveHeapBigIntResult)
+#define NodeBytecodeUseBottom 0x00000
+#define NodeBytecodeUsesAsNumber 0x04000 // The result of this computation may be used in a context that observes fractional, or bigger-than-int32, results.
+#define NodeBytecodeNeedsNegZero 0x08000 // The result of this computation may be used in a context that observes -0.
+#define NodeBytecodeUsesAsOther 0x10000 // The result of this computation may be used in a context that distinguishes between NaN and other things (like undefined).
+#define NodeBytecodeUsesAsInt 0x20000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
+#define NodeBytecodeUsesAsArrayIndex 0x40000 // The result of this computation is known to be used in a context that strongly prefers integer values, to the point that we should avoid using doubles if at all possible.
+#define NodeBytecodeUsesAsValue (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther)
+#define NodeBytecodeBackPropMask (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex)
+
#define NodeArithFlagsMask (NodeBehaviorMask | NodeBytecodeBackPropMask)
-#define NodeIsFlushed 0x40000 // Computed by CPSRethreadingPhase, will tell you which local nodes are backwards-reachable from a Flush.
+#define NodeIsFlushed 0x80000 // Computed by CPSRethreadingPhase, will tell you which local nodes are backwards-reachable from a Flush.
-#define NodeMiscFlag1 0x80000
-#define NodeMiscFlag2 0x100000
+#define NodeMiscFlag1 0x100000
+#define NodeMiscFlag2 0x200000
typedef uint32_t NodeFlags;
@@ -158,6 +158,19 @@
return true;
}
+static inline bool nodeMayHaveHeapBigInt(NodeFlags flags, RareCaseProfilingSource)
+{
+ return !!(flags & NodeMayHaveHeapBigIntResult);
+}
+
+static inline bool nodeCanSpeculateBigInt32(NodeFlags flags, RareCaseProfilingSource source)
+{
+ // We always attempt to produce BigInt32 as much as possible. If we see HeapBigInt, we observed overflow.
+ // FIXME: Extend this information by tiered profiling (from Baseline, DFG etc.).
+ // https://bugs.webkit.org/show_bug.cgi?id=211039
+ return !nodeMayHaveHeapBigInt(flags, source);
+}
+
// FIXME: Get rid of this.
// https://bugs.webkit.org/show_bug.cgi?id=131689
static inline NodeFlags canonicalResultRepresentation(NodeFlags flags)
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (260729 => 260730)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2020-04-26 21:11:50 UTC (rev 260730)
@@ -210,7 +210,12 @@
} else if (isStringOrStringObjectSpeculation(left) || isStringOrStringObjectSpeculation(right)) {
// left or right is definitely something other than a number.
changed |= mergePrediction(SpecString);
- } else if (isBigIntSpeculation(left) && isBigIntSpeculation(right))
+ }
+#if USE(BIGINT32)
+ else if (m_graph.binaryArithShouldSpeculateBigInt32(node, m_pass))
+ changed |= mergePrediction(SpecBigInt32);
+#endif
+ else if (isBigIntSpeculation(left) && isBigIntSpeculation(right))
changed |= mergePrediction(SpecBigInt);
else {
changed |= mergePrediction(SpecInt32Only);
@@ -278,7 +283,12 @@
changed |= mergePrediction(SpecInt52Any);
else
changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
- } else if (isBigIntSpeculation(left) && isBigIntSpeculation(right))
+ }
+#if USE(BIGINT32)
+ else if (m_graph.binaryArithShouldSpeculateBigInt32(node, m_pass))
+ changed |= mergePrediction(SpecBigInt32);
+#endif
+ else if (isBigIntSpeculation(left) && isBigIntSpeculation(right))
changed |= mergePrediction(SpecBigInt);
else {
changed |= mergePrediction(SpecInt32Only);
@@ -304,7 +314,12 @@
changed |= mergePrediction(SpecInt52Any);
else
changed |= mergePrediction(speculatedDoubleTypeForPrediction(prediction));
- } else if (isBigIntSpeculation(prediction))
+ }
+#if USE(BIGINT32)
+ else if (m_graph.unaryArithShouldSpeculateBigInt32(node, m_pass))
+ changed |= mergePrediction(SpecBigInt32);
+#endif
+ else if (isBigIntSpeculation(prediction))
changed |= mergePrediction(SpecBigInt);
else {
changed |= mergePrediction(SpecInt32Only);
@@ -386,7 +401,12 @@
changed |= mergePrediction(SpecInt52Any);
else
changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
- } else if (op == ValueMul && isBigIntSpeculation(left) && isBigIntSpeculation(right))
+ }
+#if USE(BIGINT32)
+ else if (op == ValueMul && m_graph.binaryArithShouldSpeculateBigInt32(node, m_pass))
+ changed |= mergePrediction(SpecBigInt32);
+#endif
+ else if (op == ValueMul && isBigIntSpeculation(left) && isBigIntSpeculation(right))
changed |= mergePrediction(SpecBigInt);
else {
changed |= mergePrediction(SpecInt32Only);
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (260729 => 260730)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2020-04-26 21:11:50 UTC (rev 260730)
@@ -4026,6 +4026,10 @@
Edge& rightChild = node->child2();
#if USE(BIGINT32)
+ // FIXME: Introduce another BigInt32 code generation: binary use kinds are BigIntUse32, but result is SpecAnyInt and accepting overflow.
+ // Let's distinguish these modes based on result type information by introducing NodeResultBigInt32.
+ // https://bugs.webkit.org/show_bug.cgi?id=210957
+ // https://bugs.webkit.org/show_bug.cgi?id=211040
if (node->isBinaryUseKind(BigInt32Use)) {
SpeculateBigInt32Operand left(this, leftChild);
SpeculateBigInt32Operand right(this, rightChild);
@@ -4040,10 +4044,9 @@
m_jit.unboxBigInt32(leftGPR, resultGPR);
m_jit.unboxBigInt32(rightGPR, tempGPR);
- // FIXME: add some way to eliminate the overflow check
MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, resultGPR, tempGPR, resultGPR);
- speculationCheck(Overflow, JSValueRegs(), 0, check);
+ speculationCheck(BigInt32Overflow, JSValueRegs(), 0, check);
m_jit.boxBigInt32(resultGPR);
jsValueResult(resultGPR, node);
@@ -4130,6 +4133,10 @@
Edge& rightChild = node->child2();
#if USE(BIGINT32)
+ // FIXME: Introduce another BigInt32 code generation: binary use kinds are BigIntUse32, but result is SpecAnyInt and accepting overflow.
+ // Let's distinguish these modes based on result type information by introducing NodeResultBigInt32.
+ // https://bugs.webkit.org/show_bug.cgi?id=210957
+ // https://bugs.webkit.org/show_bug.cgi?id=211040
if (node->binaryUseKind() == BigInt32Use) {
SpeculateBigInt32Operand left(this, node->child1());
SpeculateBigInt32Operand right(this, node->child2());
@@ -4144,10 +4151,9 @@
m_jit.unboxBigInt32(leftGPR, resultGPR);
m_jit.unboxBigInt32(rightGPR, tempGPR);
- // FIXME: add some way to eliminate the overflow check
MacroAssembler::Jump check = m_jit.branchSub32(MacroAssembler::Overflow, resultGPR, tempGPR, resultGPR);
- speculationCheck(Overflow, JSValueRegs(), 0, check);
+ speculationCheck(BigInt32Overflow, JSValueRegs(), 0, check);
m_jit.boxBigInt32(resultGPR);
jsValueResult(resultGPR, node);
@@ -4977,6 +4983,10 @@
Edge& rightChild = node->child2();
#if USE(BIGINT32)
+ // FIXME: Introduce another BigInt32 code generation: binary use kinds are BigIntUse32, but result is SpecAnyInt and accepting overflow.
+ // Let's distinguish these modes based on result type information by introducing NodeResultBigInt32.
+ // https://bugs.webkit.org/show_bug.cgi?id=210957
+ // https://bugs.webkit.org/show_bug.cgi?id=211040
if (node->binaryUseKind() == BigInt32Use) {
// FIXME: the code between compileValueAdd, compileValueSub and compileValueMul for BigInt32 is nearly identical, so try to get rid of the duplication.
SpeculateBigInt32Operand left(this, node->child1());
@@ -4992,10 +5002,9 @@
m_jit.unboxBigInt32(leftGPR, resultGPR);
m_jit.unboxBigInt32(rightGPR, tempGPR);
- // FIXME: add some way to eliminate the overflow check
MacroAssembler::Jump check = m_jit.branchMul32(MacroAssembler::Overflow, resultGPR, tempGPR, resultGPR);
- speculationCheck(Overflow, JSValueRegs(), 0, check);
+ speculationCheck(BigInt32Overflow, JSValueRegs(), 0, check);
m_jit.boxBigInt32(resultGPR);
jsValueResult(resultGPR, node);
@@ -5209,6 +5218,7 @@
Edge& rightChild = node->child2();
// FIXME: add a fast path for BigInt32. Currently we go through the slow path, because of how ugly the code for Div gets.
+ // https://bugs.webkit.org/show_bug.cgi?id=211041
if (node->isBinaryUseKind(HeapBigIntUse)) {
SpeculateCellOperand left(this, leftChild);
@@ -10802,7 +10812,7 @@
void SpeculativeJIT::speculateHeapBigInt(Edge edge)
{
- if (!needsTypeCheck(edge, SpecBigInt))
+ if (!needsTypeCheck(edge, SpecHeapBigInt))
return;
SpeculateCellOperand operand(this, edge);
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (260729 => 260730)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2020-04-26 20:02:18 UTC (rev 260729)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2020-04-26 21:11:50 UTC (rev 260730)
@@ -2143,6 +2143,10 @@
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
#if USE(BIGINT32)
+ // FIXME: Introduce another BigInt32 code generation: binary use kinds are BigIntUse32, but result is SpecAnyInt and accepting overflow.
+ // Let's distinguish these modes based on result type information by introducing NodeResultBigInt32.
+ // https://bugs.webkit.org/show_bug.cgi?id=210957
+ // https://bugs.webkit.org/show_bug.cgi?id=211040
if (m_node->isBinaryUseKind(BigInt32Use)) {
LValue left = lowBigInt32(m_node->child1());
LValue right = lowBigInt32(m_node->child2());
@@ -2151,7 +2155,7 @@
LValue unboxedRight = unboxBigInt32(right);
CheckValue* result = m_out.speculateAdd(unboxedLeft, unboxedRight);
- blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
+ blessSpeculation(result, BigInt32Overflow, noValue(), nullptr, m_origin);
LValue boxedResult = boxBigInt32(result);
setJSValue(boxedResult);
@@ -2181,6 +2185,10 @@
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
#if USE(BIGINT32)
+ // FIXME: Introduce another BigInt32 code generation: binary use kinds are BigIntUse32, but result is SpecAnyInt and accepting overflow.
+ // Let's distinguish these modes based on result type information by introducing NodeResultBigInt32.
+ // https://bugs.webkit.org/show_bug.cgi?id=210957
+ // https://bugs.webkit.org/show_bug.cgi?id=211040
if (m_node->isBinaryUseKind(BigInt32Use)) {
LValue left = lowBigInt32(m_node->child1());
LValue right = lowBigInt32(m_node->child2());
@@ -2189,7 +2197,7 @@
LValue unboxedRight = unboxBigInt32(right);
CheckValue* result = m_out.speculateSub(unboxedLeft, unboxedRight);
- blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
+ blessSpeculation(result, BigInt32Overflow, noValue(), nullptr, m_origin);
LValue boxedResult = boxBigInt32(result);
setJSValue(boxedResult);
@@ -2219,6 +2227,10 @@
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
#if USE(BIGINT32)
+ // FIXME: Introduce another BigInt32 code generation: binary use kinds are BigIntUse32, but result is SpecAnyInt and accepting overflow.
+ // Let's distinguish these modes based on result type information by introducing NodeResultBigInt32.
+ // https://bugs.webkit.org/show_bug.cgi?id=210957
+ // https://bugs.webkit.org/show_bug.cgi?id=211040
if (m_node->isBinaryUseKind(BigInt32Use)) {
LValue left = lowBigInt32(m_node->child1());
LValue right = lowBigInt32(m_node->child2());
@@ -2227,7 +2239,7 @@
LValue unboxedRight = unboxBigInt32(right);
CheckValue* result = m_out.speculateMul(unboxedLeft, unboxedRight);
- blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
+ blessSpeculation(result, BigInt32Overflow, noValue(), nullptr, m_origin);
LValue boxedResult = boxBigInt32(result);
setJSValue(boxedResult);
@@ -2627,6 +2639,7 @@
{
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
// FIXME: add a fast path for BigInt32 here
+ // https://bugs.webkit.org/show_bug.cgi?id=211041
if (m_node->isBinaryUseKind(HeapBigIntUse)) {
LValue left = lowHeapBigInt(m_node->child1());
LValue right = lowHeapBigInt(m_node->child2());