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

