| 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 |
| |