blob: 60342a14f8bf3bf88e7108c68e498cfdde11bab0 [file] [log] [blame]
CVE: CVE-2022-32923
Upstream-Status: Backport [https://github.com/WebKit/WebKit/commit/ef76e31]
[1]: https://support.apple.com/en-us/HT213495
[2]: https://bugs.webkit.org/show_bug.cgi?id=242964
Signed-off-by: Kai Kang <kai.kang@windriver.com>
From ef76e31a2a066c3d65a9c94a9e2cd88133260c1f Mon Sep 17 00:00:00 2001
From: Yusuke Suzuki <ysuzuki@apple.com>
Date: Wed, 20 Jul 2022 19:30:48 -0700
Subject: [PATCH] [JSC] BakcwardPropagationPhase should carry NaN / Infinity
handling https://bugs.webkit.org/show_bug.cgi?id=242964 rdar://96791603
Reviewed by Mark Lam.
For correctness, we should carry NaN / Infinity handling to make it more clear in the code generation site.
* Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
* Source/JavaScriptCore/dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupArithDivInt32):
(JSC::DFG::FixupPhase::fixupArithDiv):
* Source/JavaScriptCore/dfg/DFGGraph.h:
* Source/JavaScriptCore/dfg/DFGNode.h:
* Source/JavaScriptCore/dfg/DFGNodeFlags.cpp:
(JSC::DFG::dumpNodeFlags):
* Source/JavaScriptCore/dfg/DFGNodeFlags.h:
(JSC::DFG::bytecodeCanIgnoreNaNAndInfinity):
(JSC::DFG::nodeCanSpeculateInt32ForDiv):
* Source/JavaScriptCore/dfg/DFGNodeType.h:
Canonical link: https://commits.webkit.org/252675@main
---
.../dfg/DFGBackwardsPropagationPhase.cpp | 51 +++++++++++--------
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp | 6 ++-
Source/JavaScriptCore/dfg/DFGGraph.h | 11 ++++
Source/JavaScriptCore/dfg/DFGNode.h | 12 +++--
Source/JavaScriptCore/dfg/DFGNodeFlags.cpp | 10 ++--
Source/JavaScriptCore/dfg/DFGNodeFlags.h | 37 +++++++++++---
Source/JavaScriptCore/dfg/DFGNodeType.h | 3 +-
7 files changed, 91 insertions(+), 39 deletions(-)
diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
index 306ea5d6b974..83a08aff7c20 100644
--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
@@ -272,7 +272,7 @@ private:
case ValueBitNot:
case ArithBitNot: {
flags |= NodeBytecodeUsesAsInt;
- flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther);
+ flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeNeedsNaNOrInfinity | NodeBytecodeUsesAsOther);
flags &= ~NodeBytecodeUsesAsArrayIndex;
node->child1()->mergeFlags(flags);
break;
@@ -291,7 +291,7 @@ private:
case BitURShift:
case ArithIMul: {
flags |= NodeBytecodeUsesAsInt;
- flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther);
+ flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeNeedsNaNOrInfinity | NodeBytecodeUsesAsOther);
flags &= ~NodeBytecodeUsesAsArrayIndex;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
@@ -308,9 +308,9 @@ private:
case StringSlice: {
node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
- node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+ node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex | NodeBytecodeNeedsNaNOrInfinity);
if (node->child3())
- node->child3()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+ node->child3()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex | NodeBytecodeNeedsNaNOrInfinity);
break;
}
@@ -320,11 +320,11 @@ private:
if (node->numChildren() == 2)
m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsValue);
else if (node->numChildren() == 3) {
- m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+ m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex | NodeBytecodeNeedsNaNOrInfinity);
m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsValue);
} else if (node->numChildren() == 4) {
- m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
- m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+ m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex | NodeBytecodeNeedsNaNOrInfinity);
+ m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex | NodeBytecodeNeedsNaNOrInfinity);
m_graph.varArgChild(node, 3)->mergeFlags(NodeBytecodeUsesAsValue);
}
break;
@@ -345,6 +345,7 @@ private:
flags |= NodeBytecodeUsesAsNumber;
if (!m_allowNestedOverflowingAdditions)
flags |= NodeBytecodeUsesAsNumber;
+ flags |= NodeBytecodeNeedsNaNOrInfinity;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
@@ -359,6 +360,7 @@ private:
flags |= NodeBytecodeUsesAsNumber;
if (!m_allowNestedOverflowingAdditions)
flags |= NodeBytecodeUsesAsNumber;
+ flags |= NodeBytecodeNeedsNaNOrInfinity;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
@@ -366,7 +368,7 @@ private:
}
case ArithClz32: {
- flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther | ~NodeBytecodeUsesAsArrayIndex);
+ flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeNeedsNaNOrInfinity | NodeBytecodeUsesAsOther | ~NodeBytecodeUsesAsArrayIndex);
flags |= NodeBytecodeUsesAsInt;
node->child1()->mergeFlags(flags);
break;
@@ -380,6 +382,7 @@ private:
flags |= NodeBytecodeUsesAsNumber;
if (!m_allowNestedOverflowingAdditions)
flags |= NodeBytecodeUsesAsNumber;
+ flags |= NodeBytecodeNeedsNaNOrInfinity;
node->child1()->mergeFlags(flags);
node->child2()->mergeFlags(flags);
@@ -387,6 +390,7 @@ private:
}
case ArithNegate: {
+ // negation does not care about NaN, Infinity, -Infinity are converted into 0 if the result is evaluated under the integer context.
flags &= ~NodeBytecodeUsesAsOther;
node->child1()->mergeFlags(flags);
@@ -401,6 +405,7 @@ private:
flags |= NodeBytecodeUsesAsNumber;
if (!m_allowNestedOverflowingAdditions)
flags |= NodeBytecodeUsesAsNumber;
+ flags |= NodeBytecodeNeedsNaNOrInfinity;
node->child1()->mergeFlags(flags);
break;
@@ -421,7 +426,7 @@ private:
node->mergeFlags(flags);
- flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero;
+ flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeNeedsNaNOrInfinity;
flags &= ~NodeBytecodeUsesAsOther;
node->child1()->mergeFlags(flags);
@@ -431,7 +436,13 @@ private:
case ValueDiv:
case ArithDiv: {
- flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero;
+ // ArithDiv / ValueDiv need to have NodeBytecodeUsesAsNumber even if it is used in the context of integer.
+ // For example,
+ // ((@x / @y) + @z) | 0
+ // In this context, (@x / @y) can have integer context at first, but the result can be different if div
+ // generates NaN. Div and Mod are operations that can produce NaN / Infinity though only taking binary Int32 operands.
+ // Thus, we always need to check for overflow since it can affect downstream calculations.
+ flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeNeedsNaNOrInfinity;
flags &= ~NodeBytecodeUsesAsOther;
node->child1()->mergeFlags(flags);
@@ -441,7 +452,7 @@ private:
case ValueMod:
case ArithMod: {
- flags |= NodeBytecodeUsesAsNumber;
+ flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeNeedsNaNOrInfinity;
flags &= ~NodeBytecodeUsesAsOther;
node->child1()->mergeFlags(flags);
@@ -452,7 +463,7 @@ private:
case EnumeratorGetByVal:
case GetByVal: {
m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue);
- m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+ m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeNeedsNaNOrInfinity | NodeBytecodeUsesAsArrayIndex);
break;
}
@@ -461,13 +472,13 @@ private:
// Negative zero is not observable. NaN versus undefined are only observable
// in that you would get a different exception message. So, like, whatever: we
// claim here that NaN v. undefined is observable.
- node->child1()->mergeFlags(NodeBytecodeUsesAsInt | NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsArrayIndex);
+ node->child1()->mergeFlags(NodeBytecodeUsesAsInt | NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeNeedsNaNOrInfinity | NodeBytecodeUsesAsArrayIndex);
break;
}
case ToString:
case CallStringConstructor: {
- node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther);
+ node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeNeedsNaNOrInfinity);
break;
}
@@ -487,15 +498,15 @@ private:
case CompareBelowEq:
case CompareEq:
case CompareStrictEq: {
- node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther);
- node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther);
+ node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeNeedsNaNOrInfinity);
+ node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeNeedsNaNOrInfinity);
break;
}
case PutByValDirect:
case PutByVal: {
m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue);
- m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+ m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex | NodeBytecodeNeedsNaNOrInfinity);
m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsValue);
break;
}
@@ -508,20 +519,20 @@ private:
// then -0 and 0 are treated the same. We don't need NodeBytecodeUsesAsOther
// because if all of the cases are integers then NaN and undefined are
// treated the same (i.e. they will take default).
- node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsInt);
+ node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsInt | NodeBytecodeNeedsNaNOrInfinity);
break;
case SwitchChar: {
// We don't need NodeBytecodeNeedsNegZero because if the cases are all strings
// then -0 and 0 are treated the same. We don't need NodeBytecodeUsesAsOther
// because if all of the cases are single-character strings then NaN
// and undefined are treated the same (i.e. they will take default).
- node->child1()->mergeFlags(NodeBytecodeUsesAsNumber);
+ node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNaNOrInfinity);
break;
}
case SwitchString:
// We don't need NodeBytecodeNeedsNegZero because if the cases are all strings
// then -0 and 0 are treated the same.
- node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther);
+ node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeNeedsNaNOrInfinity);
break;
case SwitchCell:
// There is currently no point to being clever here since this is used for switching
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index e8bee58ada15..b679539de2e6 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -81,7 +81,9 @@ private:
if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7IDIVSupported()) {
fixIntOrBooleanEdge(leftChild);
fixIntOrBooleanEdge(rightChild);
- if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
+ // We need to be careful about skipping overflow check because div / mod can generate non integer values
+ // from (Int32, Int32) inputs. For now, we always check non-zero divisor.
+ if (bytecodeCanTruncateInteger(node->arithNodeFlags()) && bytecodeCanIgnoreNaNAndInfinity(node->arithNodeFlags()) && bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
node->setArithMode(Arith::CheckOverflow);
@@ -122,7 +124,7 @@ private:
void fixupArithDiv(Node* node, Edge& leftChild, Edge& rightChild)
{
- if (m_graph.binaryArithShouldSpeculateInt32(node, FixupPass)) {
+ if (m_graph.divShouldSpeculateInt32(node, FixupPass)) {
fixupArithDivInt32(node, leftChild, rightChild);
return;
}
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index ca566d3a484e..284c87672849 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -373,6 +373,17 @@ public:
return shouldSpeculateInt52ForAdd(left) && shouldSpeculateInt52ForAdd(right);
}
+
+ bool divShouldSpeculateInt32(Node* node, PredictionPass pass)
+ {
+ // Even if inputs are Int32, div can generate NaN or Infinity.
+ // Thus, Overflow in div can be caused by these non integer values as well as actual Int32 overflow.
+ Node* left = node->child1().node();
+ Node* right = node->child2().node();
+
+ return Node::shouldSpeculateInt32OrBooleanForArithmetic(left, right)
+ && nodeCanSpeculateInt32ForDiv(node->arithNodeFlags(), node->sourceFor(pass));
+ }
bool binaryArithShouldSpeculateInt32(Node* node, PredictionPass pass)
{
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index f9ff50658e93..04509a3846ca 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -3308,21 +3308,25 @@ public:
out.printf(", @%u", child3()->index());
}
- NodeOrigin origin;
+ NO_UNIQUE_ADDRESS NodeOrigin origin;
+private:
+ NO_UNIQUE_ADDRESS NodeType m_op;
+
+ NO_UNIQUE_ADDRESS unsigned m_index { std::numeric_limits<unsigned>::max() };
+
+public:
// References to up to 3 children, or links to a variable length set of children.
AdjacencyList children;
private:
friend class B3::SparseCollection<Node>;
- unsigned m_index { std::numeric_limits<unsigned>::max() };
- unsigned m_op : 10; // real type is NodeType
- unsigned m_flags : 21;
// The virtual register number (spill location) associated with this .
VirtualRegister m_virtualRegister;
// The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).
unsigned m_refCount;
+ NodeFlags m_flags;
// The prediction ascribed to this node after propagation.
SpeculatedType m_prediction { SpecNone };
// Immediate values, accesses type-checked via accessors above.
diff --git a/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp b/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
index 88242947f6ef..0c53cd976c5c 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
+++ b/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
@@ -74,12 +74,14 @@ void dumpNodeFlags(PrintStream& actualOut, NodeFlags flags)
out.print(comma, "VarArgs");
if (flags & NodeResultMask) {
- if (!(flags & NodeBytecodeUsesAsNumber) && !(flags & NodeBytecodeNeedsNegZero))
+ if (!(flags & NodeBytecodeUsesAsNumber))
out.print(comma, "PureInt");
- else if (!(flags & NodeBytecodeUsesAsNumber))
- out.print(comma, "PureInt(w/ neg zero)");
- else if (!(flags & NodeBytecodeNeedsNegZero))
+ else
out.print(comma, "PureNum");
+ if (flags & NodeBytecodeNeedsNegZero)
+ out.print(comma, "NeedsNegZero");
+ if (flags & NodeBytecodeNeedsNaNOrInfinity)
+ out.print(comma, "NeedsNaNOrInfinity");
if (flags & NodeBytecodeUsesAsOther)
out.print(comma, "UseAsOther");
}
diff --git a/Source/JavaScriptCore/dfg/DFGNodeFlags.h b/Source/JavaScriptCore/dfg/DFGNodeFlags.h
index 2ebe3544f601..aa60db7e6ba0 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeFlags.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeFlags.h
@@ -61,18 +61,19 @@ namespace JSC { namespace DFG {
#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 NodeBytecodeNeedsNaNOrInfinity 0x10000 // The result of this computation may be used in a context that observes NaN or Infinity.
+#define NodeBytecodeUsesAsOther 0x20000 // The result of this computation may be used in a context that distinguishes between NaN and other things (like undefined).
+#define NodeBytecodeUsesAsInt 0x40000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
+#define NodeBytecodeUsesAsArrayIndex 0x80000 // 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 | NodeBytecodeNeedsNaNOrInfinity | NodeBytecodeUsesAsOther)
+#define NodeBytecodeBackPropMask (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeNeedsNaNOrInfinity | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex)
#define NodeArithFlagsMask (NodeBehaviorMask | NodeBytecodeBackPropMask)
-#define NodeIsFlushed 0x80000 // Computed by CPSRethreadingPhase, will tell you which local nodes are backwards-reachable from a Flush.
+#define NodeIsFlushed 0x100000 // Computed by CPSRethreadingPhase, will tell you which local nodes are backwards-reachable from a Flush.
-#define NodeMiscFlag1 0x100000
-#define NodeMiscFlag2 0x200000
+#define NodeMiscFlag1 0x200000
+#define NodeMiscFlag2 0x400000
typedef uint32_t NodeFlags;
@@ -91,6 +92,11 @@ static inline bool bytecodeCanIgnoreNegativeZero(NodeFlags flags)
return !(flags & NodeBytecodeNeedsNegZero);
}
+static inline bool bytecodeCanIgnoreNaNAndInfinity(NodeFlags flags)
+{
+ return !(flags & NodeBytecodeNeedsNaNOrInfinity);
+}
+
enum RareCaseProfilingSource {
BaselineRareCase, // Comes from slow case counting in the baseline JIT.
DFGRareCase, // Comes from OSR exit profiles.
@@ -147,6 +153,21 @@ static inline bool nodeCanSpeculateInt32(NodeFlags flags, RareCaseProfilingSourc
return true;
}
+static inline bool nodeCanSpeculateInt32ForDiv(NodeFlags flags, RareCaseProfilingSource source)
+{
+ if (nodeMayOverflowInt32(flags, source)) {
+ if (bytecodeUsesAsNumber(flags))
+ return false;
+ if (!bytecodeCanIgnoreNaNAndInfinity(flags))
+ return false;
+ }
+
+ if (nodeMayNegZero(flags, source))
+ return bytecodeCanIgnoreNegativeZero(flags);
+
+ return true;
+}
+
static inline bool nodeCanSpeculateInt52(NodeFlags flags, RareCaseProfilingSource source)
{
if (nodeMayOverflowInt52(flags, source))
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 8f885b570665..aad4d559ccf7 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -567,7 +567,7 @@ namespace JSC { namespace DFG {
// This enum generates a monotonically increasing id for all Node types,
// and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask).
-enum NodeType {
+enum NodeType : uint16_t {
#define DFG_OP_ENUM(opcode, flags) opcode,
FOR_EACH_DFG_OP(DFG_OP_ENUM)
#undef DFG_OP_ENUM
@@ -577,6 +577,7 @@ enum NodeType {
#define DFG_OP_COUNT(opcode, flags) + 1
constexpr unsigned numberOfNodeTypes = FOR_EACH_DFG_OP(DFG_OP_COUNT);
#undef DFG_OP_COUNT
+static_assert(numberOfNodeTypes <= UINT16_MAX);
// Specifies the default flags for each node.
inline NodeFlags defaultFlags(NodeType op)
--
2.34.1