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 From ef76e31a2a066c3d65a9c94a9e2cd88133260c1f Mon Sep 17 00:00:00 2001 From: Yusuke Suzuki 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::max() }; + +public: // References to up to 3 children, or links to a variable length set of children. AdjacencyList children; private: friend class B3::SparseCollection; - unsigned m_index { std::numeric_limits::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