Split ArithProfile into a Unary and a Binary version
https://bugs.webkit.org/show_bug.cgi?id=202832

Reviewed by Keith Miller.

ArithProfile was for a long time only used for add/sub/mul/div, but recently it started being used for negate. And it will soon also have to be used for inc and dec due to BigInt.
So in this patch I make a separate version that only has the data for a single argument, and thus takes half as much memory.

* bytecode/ArithProfile.cpp:
(JSC::ArithProfile<BitfieldType>::emitObserveResult):
(JSC::ArithProfile<BitfieldType>::shouldEmitSetDouble const):
(JSC::ArithProfile<BitfieldType>::emitSetDouble const):
(JSC::ArithProfile<BitfieldType>::shouldEmitSetNonNumeric const):
(JSC::ArithProfile<BitfieldType>::shouldEmitSetBigInt const):
(JSC::ArithProfile<BitfieldType>::emitSetNonNumeric const):
(JSC::ArithProfile<BitfieldType>::emitSetBigInt const):
(WTF::printInternal):
* bytecode/ArithProfile.h:
(JSC::ArithProfile::didObserveNonInt32 const):
(JSC::ArithProfile::didObserveDouble const):
(JSC::ArithProfile::didObserveNonNegZeroDouble const):
(JSC::ArithProfile::didObserveNegZeroDouble const):
(JSC::ArithProfile::didObserveNonNumeric const):
(JSC::ArithProfile::didObserveBigInt const):
(JSC::ArithProfile::didObserveInt32Overflow const):
(JSC::ArithProfile::didObserveInt52Overflow const):
(JSC::ArithProfile::setObservedNonNegZeroDouble):
(JSC::ArithProfile::setObservedNegZeroDouble):
(JSC::ArithProfile::setObservedNonNumeric):
(JSC::ArithProfile::setObservedBigInt):
(JSC::ArithProfile::setObservedInt32Overflow):
(JSC::ArithProfile::setObservedInt52Overflow):
(JSC::ArithProfile::observeResult):
(JSC::ArithProfile::addressOfBits const):
(JSC::ArithProfile::bits const):
(JSC::ArithProfile::ArithProfile):
(JSC::ArithProfile::hasBits const):
(JSC::ArithProfile::setBit):
(JSC::UnaryArithProfile::UnaryArithProfile):
(JSC::UnaryArithProfile::observedIntBits):
(JSC::UnaryArithProfile::observedNumberBits):
(JSC::UnaryArithProfile::argResultType const):
(JSC::UnaryArithProfile::argObservedType const):
(JSC::UnaryArithProfile::setArgObservedType):
(JSC::UnaryArithProfile::argSawInt32):
(JSC::UnaryArithProfile::argSawNumber):
(JSC::UnaryArithProfile::argSawNonNumber):
(JSC::UnaryArithProfile::observeArg):
(JSC::UnaryArithProfile::isObservedTypeEmpty):
(JSC::BinaryArithProfile::BinaryArithProfile):
(JSC::BinaryArithProfile::observedIntIntBits):
(JSC::BinaryArithProfile::observedNumberIntBits):
(JSC::BinaryArithProfile::observedIntNumberBits):
(JSC::BinaryArithProfile::observedNumberNumberBits):
(JSC::BinaryArithProfile::observeLHS):
(JSC::BinaryArithProfile::observeLHSAndRHS):
(JSC::BinaryArithProfile::isObservedTypeEmpty):
* bytecode/BytecodeList.rb:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::addJITAddIC):
(JSC::CodeBlock::addJITMulIC):
(JSC::CodeBlock::addJITSubIC):
(JSC::CodeBlock::addJITNegIC):
(JSC::CodeBlock::binaryArithProfileForBytecodeOffset):
(JSC::CodeBlock::unaryArithProfileForBytecodeOffset):
(JSC::CodeBlock::binaryArithProfileForPC):
(JSC::CodeBlock::unaryArithProfileForPC):
(JSC::CodeBlock::couldTakeSpecialFastCase):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::addMathIC):
* bytecode/Fits.h:
* bytecode/MethodOfGettingAValueProfile.cpp:
(JSC::MethodOfGettingAValueProfile::emitReportValue const):
(JSC::MethodOfGettingAValueProfile::reportValue):
* bytecode/MethodOfGettingAValueProfile.h:
(JSC::MethodOfGettingAValueProfile::MethodOfGettingAValueProfile):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitUnaryOp):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::UnaryOpNode::emitBytecode):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::makeSafe):
(JSC::DFG::ByteCodeParser::makeDivSafe):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::methodOfGettingAValueProfileFor):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileValueAdd):
(JSC::DFG::SpeculativeJIT::compileValueSub):
(JSC::DFG::SpeculativeJIT::compileValueNegate):
(JSC::DFG::SpeculativeJIT::compileValueMul):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileValueAdd):
(JSC::FTL::DFG::LowerDFGToB3::compileValueSub):
(JSC::FTL::DFG::LowerDFGToB3::compileValueMul):
(JSC::FTL::DFG::LowerDFGToB3::compileUnaryMathIC):
(JSC::FTL::DFG::LowerDFGToB3::compileBinaryMathIC):
(JSC::FTL::DFG::LowerDFGToB3::compileArithAddOrSub):
(JSC::FTL::DFG::LowerDFGToB3::compileValueNegate):
* jit/JIT.h:
* jit/JITAddGenerator.cpp:
(JSC::JITAddGenerator::generateInline):
(JSC::JITAddGenerator::generateFastPath):
* jit/JITAddGenerator.h:
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_op_negate):
(JSC::JIT::emit_op_add):
(JSC::JIT::emitMathICFast):
(JSC::JIT::emitMathICSlow):
(JSC::JIT::emit_op_div):
(JSC::JIT::emit_op_mul):
(JSC::JIT::emit_op_sub):
* jit/JITDivGenerator.cpp:
(JSC::JITDivGenerator::generateFastPath):
* jit/JITDivGenerator.h:
(JSC::JITDivGenerator::JITDivGenerator):
* jit/JITInlines.h:
(JSC::JIT::copiedArithProfile):
* jit/JITMathIC.h:
(JSC::JITMathIC::JITMathIC):
(JSC::JITMathIC::generateInline):
(JSC::JITMathIC::arithProfile const):
(JSC::isBinaryProfileEmpty):
(JSC::JITBinaryMathIC::JITBinaryMathIC):
(JSC::isUnaryProfileEmpty):
(JSC::JITUnaryMathIC::JITUnaryMathIC):
* jit/JITMulGenerator.cpp:
(JSC::JITMulGenerator::generateInline):
(JSC::JITMulGenerator::generateFastPath):
* jit/JITMulGenerator.h:
* jit/JITNegGenerator.cpp:
(JSC::JITNegGenerator::generateInline):
(JSC::JITNegGenerator::generateFastPath):
* jit/JITNegGenerator.h:
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITSubGenerator.cpp:
(JSC::JITSubGenerator::generateInline):
(JSC::JITSubGenerator::generateFastPath):
* jit/JITSubGenerator.h:
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LLIntOffsetsExtractor.cpp:
(JSC::LLIntOffsetsExtractor::dummy):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* parser/ResultType.h:
(JSC::ResultType::ResultType):
* runtime/CommonSlowPaths.cpp:
(JSC::updateArithProfileForUnaryArithOp):
(JSC::updateArithProfileForBinaryArithOp):
(JSC::SLOW_PATH_DECL):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@251090 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 639dbea..5eb2158 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,159 @@
+2019-10-14  Robin Morisset  <rmorisset@apple.com>
+
+        Split ArithProfile into a Unary and a Binary version
+        https://bugs.webkit.org/show_bug.cgi?id=202832
+
+        Reviewed by Keith Miller.
+
+        ArithProfile was for a long time only used for add/sub/mul/div, but recently it started being used for negate. And it will soon also have to be used for inc and dec due to BigInt.
+        So in this patch I make a separate version that only has the data for a single argument, and thus takes half as much memory.
+
+        * bytecode/ArithProfile.cpp:
+        (JSC::ArithProfile<BitfieldType>::emitObserveResult):
+        (JSC::ArithProfile<BitfieldType>::shouldEmitSetDouble const):
+        (JSC::ArithProfile<BitfieldType>::emitSetDouble const):
+        (JSC::ArithProfile<BitfieldType>::shouldEmitSetNonNumeric const):
+        (JSC::ArithProfile<BitfieldType>::shouldEmitSetBigInt const):
+        (JSC::ArithProfile<BitfieldType>::emitSetNonNumeric const):
+        (JSC::ArithProfile<BitfieldType>::emitSetBigInt const):
+        (WTF::printInternal):
+        * bytecode/ArithProfile.h:
+        (JSC::ArithProfile::didObserveNonInt32 const):
+        (JSC::ArithProfile::didObserveDouble const):
+        (JSC::ArithProfile::didObserveNonNegZeroDouble const):
+        (JSC::ArithProfile::didObserveNegZeroDouble const):
+        (JSC::ArithProfile::didObserveNonNumeric const):
+        (JSC::ArithProfile::didObserveBigInt const):
+        (JSC::ArithProfile::didObserveInt32Overflow const):
+        (JSC::ArithProfile::didObserveInt52Overflow const):
+        (JSC::ArithProfile::setObservedNonNegZeroDouble):
+        (JSC::ArithProfile::setObservedNegZeroDouble):
+        (JSC::ArithProfile::setObservedNonNumeric):
+        (JSC::ArithProfile::setObservedBigInt):
+        (JSC::ArithProfile::setObservedInt32Overflow):
+        (JSC::ArithProfile::setObservedInt52Overflow):
+        (JSC::ArithProfile::observeResult):
+        (JSC::ArithProfile::addressOfBits const):
+        (JSC::ArithProfile::bits const):
+        (JSC::ArithProfile::ArithProfile):
+        (JSC::ArithProfile::hasBits const):
+        (JSC::ArithProfile::setBit):
+        (JSC::UnaryArithProfile::UnaryArithProfile):
+        (JSC::UnaryArithProfile::observedIntBits):
+        (JSC::UnaryArithProfile::observedNumberBits):
+        (JSC::UnaryArithProfile::argResultType const):
+        (JSC::UnaryArithProfile::argObservedType const):
+        (JSC::UnaryArithProfile::setArgObservedType):
+        (JSC::UnaryArithProfile::argSawInt32):
+        (JSC::UnaryArithProfile::argSawNumber):
+        (JSC::UnaryArithProfile::argSawNonNumber):
+        (JSC::UnaryArithProfile::observeArg):
+        (JSC::UnaryArithProfile::isObservedTypeEmpty):
+        (JSC::BinaryArithProfile::BinaryArithProfile):
+        (JSC::BinaryArithProfile::observedIntIntBits):
+        (JSC::BinaryArithProfile::observedNumberIntBits):
+        (JSC::BinaryArithProfile::observedIntNumberBits):
+        (JSC::BinaryArithProfile::observedNumberNumberBits):
+        (JSC::BinaryArithProfile::observeLHS):
+        (JSC::BinaryArithProfile::observeLHSAndRHS):
+        (JSC::BinaryArithProfile::isObservedTypeEmpty):
+        * bytecode/BytecodeList.rb:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::addJITAddIC):
+        (JSC::CodeBlock::addJITMulIC):
+        (JSC::CodeBlock::addJITSubIC):
+        (JSC::CodeBlock::addJITNegIC):
+        (JSC::CodeBlock::binaryArithProfileForBytecodeOffset):
+        (JSC::CodeBlock::unaryArithProfileForBytecodeOffset):
+        (JSC::CodeBlock::binaryArithProfileForPC):
+        (JSC::CodeBlock::unaryArithProfileForPC):
+        (JSC::CodeBlock::couldTakeSpecialFastCase):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::addMathIC):
+        * bytecode/Fits.h:
+        * bytecode/MethodOfGettingAValueProfile.cpp:
+        (JSC::MethodOfGettingAValueProfile::emitReportValue const):
+        (JSC::MethodOfGettingAValueProfile::reportValue):
+        * bytecode/MethodOfGettingAValueProfile.h:
+        (JSC::MethodOfGettingAValueProfile::MethodOfGettingAValueProfile):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitUnaryOp):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::UnaryOpNode::emitBytecode):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::makeSafe):
+        (JSC::DFG::ByteCodeParser::makeDivSafe):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::methodOfGettingAValueProfileFor):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileValueAdd):
+        (JSC::DFG::SpeculativeJIT::compileValueSub):
+        (JSC::DFG::SpeculativeJIT::compileValueNegate):
+        (JSC::DFG::SpeculativeJIT::compileValueMul):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueAdd):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueSub):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueMul):
+        (JSC::FTL::DFG::LowerDFGToB3::compileUnaryMathIC):
+        (JSC::FTL::DFG::LowerDFGToB3::compileBinaryMathIC):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithAddOrSub):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueNegate):
+        * jit/JIT.h:
+        * jit/JITAddGenerator.cpp:
+        (JSC::JITAddGenerator::generateInline):
+        (JSC::JITAddGenerator::generateFastPath):
+        * jit/JITAddGenerator.h:
+        * jit/JITArithmetic.cpp:
+        (JSC::JIT::emit_op_negate):
+        (JSC::JIT::emit_op_add):
+        (JSC::JIT::emitMathICFast):
+        (JSC::JIT::emitMathICSlow):
+        (JSC::JIT::emit_op_div):
+        (JSC::JIT::emit_op_mul):
+        (JSC::JIT::emit_op_sub):
+        * jit/JITDivGenerator.cpp:
+        (JSC::JITDivGenerator::generateFastPath):
+        * jit/JITDivGenerator.h:
+        (JSC::JITDivGenerator::JITDivGenerator):
+        * jit/JITInlines.h:
+        (JSC::JIT::copiedArithProfile):
+        * jit/JITMathIC.h:
+        (JSC::JITMathIC::JITMathIC):
+        (JSC::JITMathIC::generateInline):
+        (JSC::JITMathIC::arithProfile const):
+        (JSC::isBinaryProfileEmpty):
+        (JSC::JITBinaryMathIC::JITBinaryMathIC):
+        (JSC::isUnaryProfileEmpty):
+        (JSC::JITUnaryMathIC::JITUnaryMathIC):
+        * jit/JITMulGenerator.cpp:
+        (JSC::JITMulGenerator::generateInline):
+        (JSC::JITMulGenerator::generateFastPath):
+        * jit/JITMulGenerator.h:
+        * jit/JITNegGenerator.cpp:
+        (JSC::JITNegGenerator::generateInline):
+        (JSC::JITNegGenerator::generateFastPath):
+        * jit/JITNegGenerator.h:
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * jit/JITSubGenerator.cpp:
+        (JSC::JITSubGenerator::generateInline):
+        (JSC::JITSubGenerator::generateFastPath):
+        * jit/JITSubGenerator.h:
+        * llint/LLIntData.cpp:
+        (JSC::LLInt::Data::performAssertions):
+        * llint/LLIntOffsetsExtractor.cpp:
+        (JSC::LLIntOffsetsExtractor::dummy):
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * parser/ResultType.h:
+        (JSC::ResultType::ResultType):
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::updateArithProfileForUnaryArithOp):
+        (JSC::updateArithProfileForBinaryArithOp):
+        (JSC::SLOW_PATH_DECL):
+
 2019-10-14  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [JSC] GetterSetter should be JSCell, not JSObject
diff --git a/Source/JavaScriptCore/bytecode/ArithProfile.cpp b/Source/JavaScriptCore/bytecode/ArithProfile.cpp
index 999933b..05ee78a 100644
--- a/Source/JavaScriptCore/bytecode/ArithProfile.cpp
+++ b/Source/JavaScriptCore/bytecode/ArithProfile.cpp
@@ -32,7 +32,8 @@
 namespace JSC {
 
 #if ENABLE(JIT)
-void ArithProfile::emitObserveResult(CCallHelpers& jit, JSValueRegs regs, TagRegistersMode mode)
+template<typename BitfieldType>
+void ArithProfile<BitfieldType>::emitObserveResult(CCallHelpers& jit, JSValueRegs regs, TagRegistersMode mode)
 {
     if (!shouldEmitSetDouble() && !shouldEmitSetNonNumeric() && !shouldEmitSetBigInt())
         return;
@@ -58,41 +59,50 @@
     done.link(&jit);
 }
 
-bool ArithProfile::shouldEmitSetDouble() const
+template<typename BitfieldType>
+bool ArithProfile<BitfieldType>::shouldEmitSetDouble() const
 {
-    uint32_t mask = ArithProfile::Int32Overflow | ArithProfile::Int52Overflow | ArithProfile::NegZeroDouble | ArithProfile::NonNegZeroDouble;
+    uint32_t mask = Int32Overflow | Int52Overflow | NegZeroDouble | NonNegZeroDouble;
     return (m_bits & mask) != mask;
 }
 
-void ArithProfile::emitSetDouble(CCallHelpers& jit) const
+template<typename BitfieldType>
+void ArithProfile<BitfieldType>::emitSetDouble(CCallHelpers& jit) const
 {
     if (shouldEmitSetDouble())
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::Int32Overflow | ArithProfile::Int52Overflow | ArithProfile::NegZeroDouble | ArithProfile::NonNegZeroDouble), CCallHelpers::AbsoluteAddress(addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(Int32Overflow | Int52Overflow | NegZeroDouble | NonNegZeroDouble), CCallHelpers::AbsoluteAddress(addressOfBits()));
 }
 
-bool ArithProfile::shouldEmitSetNonNumeric() const
+template<typename BitfieldType>
+bool ArithProfile<BitfieldType>::shouldEmitSetNonNumeric() const
 {
     uint32_t mask = ArithProfile::NonNumeric;
     return (m_bits & mask) != mask;
 }
 
-bool ArithProfile::shouldEmitSetBigInt() const
+template<typename BitfieldType>
+bool ArithProfile<BitfieldType>::shouldEmitSetBigInt() const
 {
     uint32_t mask = ArithProfile::BigInt;
     return (m_bits & mask) != mask;
 }
 
-void ArithProfile::emitSetNonNumeric(CCallHelpers& jit) const
+template<typename BitfieldType>
+void ArithProfile<BitfieldType>::emitSetNonNumeric(CCallHelpers& jit) const
 {
     if (shouldEmitSetNonNumeric())
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::NonNumeric), CCallHelpers::AbsoluteAddress(addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(NonNumeric), CCallHelpers::AbsoluteAddress(addressOfBits()));
 }
 
-void ArithProfile::emitSetBigInt(CCallHelpers& jit) const
+template<typename BitfieldType>
+void ArithProfile<BitfieldType>::emitSetBigInt(CCallHelpers& jit) const
 {
     if (shouldEmitSetBigInt())
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::BigInt), CCallHelpers::AbsoluteAddress(addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(BigInt), CCallHelpers::AbsoluteAddress(addressOfBits()));
 }
+
+template class ArithProfile<uint16_t>; // Generate the implementations for UnaryArithProfile
+template class ArithProfile<uint32_t>; // Generate the implementations for BinaryArithProfile
 #endif // ENABLE(JIT)
 
 } // namespace JSC
@@ -101,7 +111,52 @@
     
 using namespace JSC;
 
-void printInternal(PrintStream& out, const ArithProfile& profile)
+void printInternal(PrintStream& out, const UnaryArithProfile& profile)
+{
+    const char* separator = "";
+
+    out.print("Result:<");
+    if (!profile.didObserveNonInt32()) {
+        out.print("Int32");
+        separator = "|";
+    } else {
+        if (profile.didObserveNegZeroDouble()) {
+            out.print(separator, "NegZeroDouble");
+            separator = "|";
+        }
+        if (profile.didObserveNonNegZeroDouble()) {
+            out.print(separator, "NonNegZeroDouble");
+            separator = "|";
+        }
+        if (profile.didObserveNonNumeric()) {
+            out.print(separator, "NonNumeric");
+            separator = "|";
+        }
+        if (profile.didObserveInt32Overflow()) {
+            out.print(separator, "Int32Overflow");
+            separator = "|";
+        }
+        if (profile.didObserveInt52Overflow()) {
+            out.print(separator, "Int52Overflow");
+            separator = "|";
+        }
+        if (profile.didObserveBigInt()) {
+            out.print(separator, "BigInt");
+            separator = "|";
+        }
+    }
+    out.print(">");
+
+    out.print(" Arg ObservedType:<");
+    out.print(profile.argObservedType());
+    out.print(">");
+
+    out.print(" Arg ResultType:<");
+    out.print(RawPointer(bitwise_cast<void*>(static_cast<uintptr_t>(profile.argResultType().bits()))));
+    out.print(">");
+}
+
+void printInternal(PrintStream& out, const BinaryArithProfile& profile)
 {
     const char* separator = "";
 
diff --git a/Source/JavaScriptCore/bytecode/ArithProfile.h b/Source/JavaScriptCore/bytecode/ArithProfile.h
index fcc4e28..679a05f 100644
--- a/Source/JavaScriptCore/bytecode/ArithProfile.h
+++ b/Source/JavaScriptCore/bytecode/ArithProfile.h
@@ -66,102 +66,9 @@
     uint8_t m_bits { 0 };
 };
 
-struct ArithProfile {
-private:
-    static constexpr uint32_t numberOfFlagBits = 6;
-    static constexpr uint32_t rhsResultTypeShift = numberOfFlagBits;
-    static constexpr uint32_t lhsResultTypeShift = rhsResultTypeShift + ResultType::numBitsNeeded;
-    static constexpr uint32_t rhsObservedTypeShift = lhsResultTypeShift + ResultType::numBitsNeeded;
-    static constexpr uint32_t lhsObservedTypeShift = rhsObservedTypeShift + ObservedType::numBitsNeeded;
-
-    static_assert(ObservedType::numBitsNeeded == 3, "We make a hard assumption about that here.");
-    static constexpr uint32_t clearRhsObservedTypeBitMask = static_cast<uint32_t>(~((1 << rhsObservedTypeShift) | (1 << (rhsObservedTypeShift + 1)) | (1 << (rhsObservedTypeShift + 2))));
-    static constexpr uint32_t clearLhsObservedTypeBitMask = static_cast<uint32_t>(~((1 << lhsObservedTypeShift) | (1 << (lhsObservedTypeShift + 1)) | (1 << (lhsObservedTypeShift + 2))));
-
-    static constexpr uint32_t resultTypeMask = (1 << ResultType::numBitsNeeded) - 1;
-    static constexpr uint32_t observedTypeMask = (1 << ObservedType::numBitsNeeded) - 1;
-
-    enum class ConstantTag { Constant };
-
+template <typename BitfieldType>
+class ArithProfile {
 public:
-    static constexpr uint32_t specialFastPathBit = 1 << (lhsObservedTypeShift + ObservedType::numBitsNeeded);
-    static_assert((lhsObservedTypeShift + ObservedType::numBitsNeeded) <= (sizeof(uint32_t) * 8) - 1, "Should fit in a uint32_t.");
-    static_assert(!(specialFastPathBit & ~clearLhsObservedTypeBitMask), "These bits should not intersect.");
-    static_assert(specialFastPathBit & clearLhsObservedTypeBitMask, "These bits should intersect.");
-    static_assert(specialFastPathBit > ~clearLhsObservedTypeBitMask, "These bits should not intersect and specialFastPathBit should be a higher bit.");
-
-    ArithProfile(ResultType arg)
-        : ArithProfile(ConstantTag::Constant, arg)
-    {
-        ASSERT(lhsResultType().bits() == arg.bits());
-        ASSERT(lhsObservedType().isEmpty());
-        ASSERT(rhsObservedType().isEmpty());
-    }
-
-    ArithProfile(ResultType lhs, ResultType rhs)
-        : ArithProfile(ConstantTag::Constant, lhs, rhs)
-    {
-        ASSERT(lhsResultType().bits() == lhs.bits() && rhsResultType().bits() == rhs.bits());
-        ASSERT(lhsObservedType().isEmpty());
-        ASSERT(rhsObservedType().isEmpty());
-    }
-
-    ArithProfile(OperandTypes types)
-        : ArithProfile(types.first(), types.second())
-    { }
-
-    ArithProfile() = default;
-
-    static constexpr ArithProfile fromInt(uint32_t bits)
-    {
-        return ArithProfile { ConstantTag::Constant, bits };
-    }
-
-    static constexpr ArithProfile observedUnaryInt()
-    {
-        constexpr ObservedType observedInt32 { ObservedType().withInt32() };
-        constexpr uint32_t bits = observedInt32.bits() << lhsObservedTypeShift;
-        static_assert(bits == 0x800000, "");
-        return fromInt(bits);
-    }
-    static constexpr ArithProfile observedUnaryNumber()
-    {
-        constexpr ObservedType observedNumber { ObservedType().withNumber() };
-        constexpr uint32_t bits = observedNumber.bits() << lhsObservedTypeShift;
-        static_assert(bits == 0x1000000, "");
-        return fromInt(bits);
-    }
-    static constexpr ArithProfile observedBinaryIntInt()
-    {
-        constexpr ObservedType observedInt32 { ObservedType().withInt32() };
-        constexpr uint32_t bits = (observedInt32.bits() << lhsObservedTypeShift) | (observedInt32.bits() << rhsObservedTypeShift);
-        static_assert(bits == 0x900000, "");
-        return fromInt(bits);
-    }
-    static constexpr ArithProfile observedBinaryNumberInt()
-    {
-        constexpr ObservedType observedNumber { ObservedType().withNumber() };
-        constexpr ObservedType observedInt32 { ObservedType().withInt32() };
-        constexpr uint32_t bits = (observedNumber.bits() << lhsObservedTypeShift) | (observedInt32.bits() << rhsObservedTypeShift);
-        static_assert(bits == 0x1100000, "");
-        return fromInt(bits);
-    }
-    static constexpr ArithProfile observedBinaryIntNumber()
-    {
-        constexpr ObservedType observedNumber { ObservedType().withNumber() };
-        constexpr ObservedType observedInt32 { ObservedType().withInt32() };
-        constexpr uint32_t bits = (observedInt32.bits() << lhsObservedTypeShift) | (observedNumber.bits() << rhsObservedTypeShift);
-        static_assert(bits == 0xa00000, "");
-        return fromInt(bits);
-    }
-    static constexpr ArithProfile observedBinaryNumberNumber()
-    {
-        constexpr ObservedType observedNumber { ObservedType().withNumber() };
-        constexpr uint32_t bits = (observedNumber.bits() << lhsObservedTypeShift) | (observedNumber.bits() << rhsObservedTypeShift);
-        static_assert(bits == 0x1200000, "");
-        return fromInt(bits);
-    }
-
     enum ObservedResults {
         NonNegZeroDouble = 1 << 0,
         NegZeroDouble    = 1 << 1,
@@ -170,6 +77,231 @@
         Int52Overflow    = 1 << 4,
         BigInt           = 1 << 5,
     };
+    static constexpr uint32_t observedResultsNumBitsNeeded = 6;
+
+    bool didObserveNonInt32() const { return hasBits(NonNegZeroDouble | NegZeroDouble | NonNumeric | BigInt); }
+    bool didObserveDouble() const { return hasBits(NonNegZeroDouble | NegZeroDouble); }
+    bool didObserveNonNegZeroDouble() const { return hasBits(NonNegZeroDouble); }
+    bool didObserveNegZeroDouble() const { return hasBits(NegZeroDouble); }
+    bool didObserveNonNumeric() const { return hasBits(NonNumeric); }
+    bool didObserveBigInt() const { return hasBits(BigInt); }
+    bool didObserveInt32Overflow() const { return hasBits(Int32Overflow); }
+    bool didObserveInt52Overflow() const { return hasBits(Int52Overflow); }
+
+    void setObservedNonNegZeroDouble() { setBit(NonNegZeroDouble); }
+    void setObservedNegZeroDouble() { setBit(NegZeroDouble); }
+    void setObservedNonNumeric() { setBit(NonNumeric); }
+    void setObservedBigInt() { setBit(BigInt); }
+    void setObservedInt32Overflow() { setBit(Int32Overflow); }
+    void setObservedInt52Overflow() { setBit(Int52Overflow); }
+
+    void observeResult(JSValue value)
+    {
+        if (value.isInt32())
+            return;
+        if (value.isNumber()) {
+            m_bits |= Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble;
+            return;
+        }
+        if (value && value.isBigInt()) {
+            m_bits |= BigInt;
+            return;
+        }
+        m_bits |= NonNumeric;
+    }
+
+    const void* addressOfBits() const { return &m_bits; }
+
+#if ENABLE(JIT)
+    // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble) if it sees a
+    // double. Sets NonNumeric if it sees a non-numeric.
+    void emitObserveResult(CCallHelpers&, JSValueRegs, TagRegistersMode = HaveTagRegisters);
+
+    // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble).
+    bool shouldEmitSetDouble() const;
+    void emitSetDouble(CCallHelpers&) const;
+
+    // Sets NonNumber.
+    void emitSetNonNumeric(CCallHelpers&) const;
+    bool shouldEmitSetNonNumeric() const;
+
+    // Sets BigInt
+    void emitSetBigInt(CCallHelpers&) const;
+    bool shouldEmitSetBigInt() const;
+#endif // ENABLE(JIT)
+
+    constexpr uint32_t bits() const { return m_bits; }
+
+protected:
+    ArithProfile(BitfieldType bits)
+        : m_bits(bits)
+    {
+    }
+
+    bool hasBits(int mask) const { return m_bits & mask; }
+    void setBit(int mask) { m_bits |= mask; }
+
+    BitfieldType m_bits { 0 }; // We take care to update m_bits only in a single operation. We don't ever store an inconsistent bit representation to it.
+};
+
+/* This class stores the following components in 16 bits:
+ * - ObservedResults
+ * - ResultType for the argument
+ * - ObservedType for the argument
+ */
+class UnaryArithProfile : public ArithProfile<uint16_t> {
+    static constexpr unsigned argResultTypeShift = observedResultsNumBitsNeeded;
+    static constexpr unsigned argObservedTypeShift = argResultTypeShift + ResultType::numBitsNeeded;
+
+    static_assert(argObservedTypeShift + ObservedType::numBitsNeeded <= sizeof(uint16_t) * 8, "Should fit in a uint16_t");
+
+    static constexpr uint16_t clearArgObservedTypeBitMask = static_cast<uint16_t>(~(0b111 << argObservedTypeShift));
+
+    static constexpr uint16_t resultTypeMask = (1 << ResultType::numBitsNeeded) - 1;
+    static constexpr uint16_t observedTypeMask = (1 << ObservedType::numBitsNeeded) - 1;
+
+public:
+    UnaryArithProfile(ResultType arg)
+        : ArithProfile<uint16_t>(arg.bits() << argResultTypeShift)
+    {
+        ASSERT(argResultType().bits() == arg.bits());
+        ASSERT(argObservedType().isEmpty());
+        ASSERT(argObservedType().isEmpty());
+    }
+
+    UnaryArithProfile()
+        : UnaryArithProfile(ResultType::unknownType())
+    {
+    }
+
+    static constexpr uint16_t observedIntBits()
+    {
+        constexpr ObservedType observedInt32 { ObservedType().withInt32() };
+        constexpr uint16_t bits = observedInt32.bits() << argObservedTypeShift;
+        static_assert(bits == 0x2000, "");
+        return bits;
+    }
+    static constexpr uint16_t observedNumberBits()
+    {
+        constexpr ObservedType observedNumber { ObservedType().withNumber() };
+        constexpr uint16_t bits = observedNumber.bits() << argObservedTypeShift;
+        static_assert(bits == 0x4000, "");
+        return bits;
+    }
+
+    ResultType argResultType() const { return ResultType((m_bits >> argResultTypeShift) & resultTypeMask); }
+
+    constexpr ObservedType argObservedType() const { return ObservedType((m_bits >> argObservedTypeShift) & observedTypeMask); }
+    void setArgObservedType(ObservedType type)
+    {
+        uint16_t bits = m_bits;
+        bits &= clearArgObservedTypeBitMask;
+        bits |= type.bits() << argObservedTypeShift;
+        m_bits = bits;
+        ASSERT(argObservedType() == type);
+    }
+
+    void argSawInt32() { setArgObservedType(argObservedType().withInt32()); }
+    void argSawNumber() { setArgObservedType(argObservedType().withNumber()); }
+    void argSawNonNumber() { setArgObservedType(argObservedType().withNonNumber()); }
+
+    void observeArg(JSValue arg)
+    {
+        UnaryArithProfile newProfile = *this;
+        if (arg.isNumber()) {
+            if (arg.isInt32())
+                newProfile.argSawInt32();
+            else
+                newProfile.argSawNumber();
+        } else
+            newProfile.argSawNonNumber();
+
+        m_bits = newProfile.bits();
+    }
+
+    bool isObservedTypeEmpty()
+    {
+        return argObservedType().isEmpty();
+    }
+
+    friend class JSC::LLIntOffsetsExtractor;
+};
+
+/* This class stores the following components in 32 bits:
+ * - ObservedResults
+ * - ResultType for right-hand-side
+ * - ResultType for left-hand-side
+ * - ObservedType for right-hand-side
+ * - ObservedType for left-hand-side
+ * - a bit used by division to indicate whether a special fast path was taken
+ */
+class BinaryArithProfile : public ArithProfile<uint32_t> {
+    static constexpr uint32_t rhsResultTypeShift = observedResultsNumBitsNeeded;
+    static constexpr uint32_t lhsResultTypeShift = rhsResultTypeShift + ResultType::numBitsNeeded;
+    static constexpr uint32_t rhsObservedTypeShift = lhsResultTypeShift + ResultType::numBitsNeeded;
+    static constexpr uint32_t lhsObservedTypeShift = rhsObservedTypeShift + ObservedType::numBitsNeeded;
+
+    static_assert(ObservedType::numBitsNeeded == 3, "We make a hard assumption about that here.");
+    static constexpr uint32_t clearRhsObservedTypeBitMask = static_cast<uint32_t>(~(0b111 << rhsObservedTypeShift));
+    static constexpr uint32_t clearLhsObservedTypeBitMask = static_cast<uint32_t>(~(0b111 << lhsObservedTypeShift));
+
+    static constexpr uint32_t resultTypeMask = (1 << ResultType::numBitsNeeded) - 1;
+    static constexpr uint32_t observedTypeMask = (1 << ObservedType::numBitsNeeded) - 1;
+
+public:
+    static constexpr uint32_t specialFastPathBit = 1 << (lhsObservedTypeShift + ObservedType::numBitsNeeded);
+    static_assert((lhsObservedTypeShift + ObservedType::numBitsNeeded + 1) <= sizeof(uint32_t) * 8, "Should fit in a uint32_t.");
+    static_assert(!(specialFastPathBit & ~clearLhsObservedTypeBitMask), "These bits should not intersect.");
+    static_assert(specialFastPathBit & clearLhsObservedTypeBitMask, "These bits should intersect.");
+    static_assert(specialFastPathBit > ~clearLhsObservedTypeBitMask, "These bits should not intersect and specialFastPathBit should be a higher bit.");
+
+    BinaryArithProfile(ResultType lhs, ResultType rhs)
+        : ArithProfile<uint32_t>((lhs.bits() << lhsResultTypeShift) | (rhs.bits() << rhsResultTypeShift))
+    {
+        ASSERT(lhsResultType().bits() == lhs.bits() && rhsResultType().bits() == rhs.bits());
+        ASSERT(lhsObservedType().isEmpty());
+        ASSERT(rhsObservedType().isEmpty());
+    }
+
+    BinaryArithProfile(OperandTypes types)
+        : BinaryArithProfile(types.first(), types.second())
+    { }
+
+    BinaryArithProfile()
+        : BinaryArithProfile(ResultType::unknownType(), ResultType::unknownType())
+    {
+    }
+
+    static constexpr uint32_t observedIntIntBits()
+    {
+        constexpr ObservedType observedInt32 { ObservedType().withInt32() };
+        constexpr uint32_t bits = (observedInt32.bits() << lhsObservedTypeShift) | (observedInt32.bits() << rhsObservedTypeShift);
+        static_assert(bits == 0x900000, "");
+        return bits;
+    }
+    static constexpr uint32_t observedNumberIntBits()
+    {
+        constexpr ObservedType observedNumber { ObservedType().withNumber() };
+        constexpr ObservedType observedInt32 { ObservedType().withInt32() };
+        constexpr uint32_t bits = (observedNumber.bits() << lhsObservedTypeShift) | (observedInt32.bits() << rhsObservedTypeShift);
+        static_assert(bits == 0x1100000, "");
+        return bits;
+    }
+    static constexpr uint32_t observedIntNumberBits()
+    {
+        constexpr ObservedType observedNumber { ObservedType().withNumber() };
+        constexpr ObservedType observedInt32 { ObservedType().withInt32() };
+        constexpr uint32_t bits = (observedInt32.bits() << lhsObservedTypeShift) | (observedNumber.bits() << rhsObservedTypeShift);
+        static_assert(bits == 0xa00000, "");
+        return bits;
+    }
+    static constexpr uint32_t observedNumberNumberBits()
+    {
+        constexpr ObservedType observedNumber { ObservedType().withNumber() };
+        constexpr uint32_t bits = (observedNumber.bits() << lhsObservedTypeShift) | (observedNumber.bits() << rhsObservedTypeShift);
+        static_assert(bits == 0x1200000, "");
+        return bits;
+    }
 
     ResultType lhsResultType() const { return ResultType((m_bits >> lhsResultTypeShift) & resultTypeMask); }
     ResultType rhsResultType() const { return ResultType((m_bits >> rhsResultTypeShift) & resultTypeMask); }
@@ -196,39 +328,6 @@
 
     bool tookSpecialFastPath() const { return m_bits & specialFastPathBit; }
 
-    bool didObserveNonInt32() const { return hasBits(NonNegZeroDouble | NegZeroDouble | NonNumeric | BigInt); }
-    bool didObserveDouble() const { return hasBits(NonNegZeroDouble | NegZeroDouble); }
-    bool didObserveNonNegZeroDouble() const { return hasBits(NonNegZeroDouble); }
-    bool didObserveNegZeroDouble() const { return hasBits(NegZeroDouble); }
-    bool didObserveNonNumeric() const { return hasBits(NonNumeric); }
-    bool didObserveBigInt() const { return hasBits(BigInt); }
-    bool didObserveInt32Overflow() const { return hasBits(Int32Overflow); }
-    bool didObserveInt52Overflow() const { return hasBits(Int52Overflow); }
-
-    void setObservedNonNegZeroDouble() { setBit(NonNegZeroDouble); }
-    void setObservedNegZeroDouble() { setBit(NegZeroDouble); }
-    void setObservedNonNumeric() { setBit(NonNumeric); }
-    void setObservedBigInt() { setBit(BigInt); }
-    void setObservedInt32Overflow() { setBit(Int32Overflow); }
-    void setObservedInt52Overflow() { setBit(Int52Overflow); }
-
-    const void* addressOfBits() const { return &m_bits; }
-
-    void observeResult(JSValue value)
-    {
-        if (value.isInt32())
-            return;
-        if (value.isNumber()) {
-            m_bits |= Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble;
-            return;
-        }
-        if (value && value.isBigInt()) {
-            m_bits |= BigInt;
-            return;
-        }
-        m_bits |= NonNumeric;
-    }
-
     void lhsSawInt32() { setLhsObservedType(lhsObservedType().withInt32()); }
     void lhsSawNumber() { setLhsObservedType(lhsObservedType().withNumber()); }
     void lhsSawNonNumber() { setLhsObservedType(lhsObservedType().withNonNumber()); }
@@ -238,7 +337,7 @@
 
     void observeLHS(JSValue lhs)
     {
-        ArithProfile newProfile = *this;
+        BinaryArithProfile newProfile = *this;
         if (lhs.isNumber()) {
             if (lhs.isInt32())
                 newProfile.lhsSawInt32();
@@ -254,7 +353,7 @@
     {
         observeLHS(lhs);
 
-        ArithProfile newProfile = *this;
+        BinaryArithProfile newProfile = *this;
         if (rhs.isNumber()) {
             if (rhs.isInt32())
                 newProfile.rhsSawInt32();
@@ -266,47 +365,11 @@
         m_bits = newProfile.bits();
     }
 
-#if ENABLE(JIT)    
-    // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble) if it sees a
-    // double. Sets NonNumeric if it sees a non-numeric.
-    void emitObserveResult(CCallHelpers&, JSValueRegs, TagRegistersMode = HaveTagRegisters);
-    
-    // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble).
-    bool shouldEmitSetDouble() const;
-    void emitSetDouble(CCallHelpers&) const;
-    
-    // Sets NonNumber.
-    void emitSetNonNumeric(CCallHelpers&) const;
-    bool shouldEmitSetNonNumeric() const;
-
-    // Sets BigInt
-    void emitSetBigInt(CCallHelpers&) const;
-    bool shouldEmitSetBigInt() const;
-#endif // ENABLE(JIT)
-
-    constexpr uint32_t bits() const { return m_bits; }
-
-private:
-    constexpr explicit ArithProfile(ConstantTag, uint32_t bits)
-        : m_bits(bits)
+    bool isObservedTypeEmpty()
     {
+        return lhsObservedType().isEmpty() && rhsObservedType().isEmpty();
     }
 
-    constexpr ArithProfile(ConstantTag, ResultType arg)
-        : m_bits(arg.bits() << lhsResultTypeShift)
-    {
-    }
-
-    constexpr ArithProfile(ConstantTag, ResultType lhs, ResultType rhs)
-        : m_bits((lhs.bits() << lhsResultTypeShift) | (rhs.bits() << rhsResultTypeShift))
-    {
-    }
-
-    bool hasBits(int mask) const { return m_bits & mask; }
-    void setBit(int mask) { m_bits |= mask; }
-
-    uint32_t m_bits { 0 }; // We take care to update m_bits only in a single operation. We don't ever store an inconsistent bit representation to it.
-
     friend class JSC::LLIntOffsetsExtractor;
 };
 
@@ -314,7 +377,8 @@
 
 namespace WTF {
 
-void printInternal(PrintStream&, const JSC::ArithProfile&);
+void printInternal(PrintStream&, const JSC::UnaryArithProfile&);
+void printInternal(PrintStream&, const JSC::BinaryArithProfile&);
 void printInternal(PrintStream&, const JSC::ObservedType&);
 
 } // namespace WTF
diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.rb b/Source/JavaScriptCore/bytecode/BytecodeList.rb
index c086b8e..fb393ea 100644
--- a/Source/JavaScriptCore/bytecode/BytecodeList.rb
+++ b/Source/JavaScriptCore/bytecode/BytecodeList.rb
@@ -41,6 +41,7 @@
     :JSType,
     :JSValue,
     :LLIntCallLinkInfo,
+    :ResultType,
     :OperandTypes,
     :ProfileTypeBytecodeFlag,
     :PropertyOffset,
@@ -57,7 +58,8 @@
 
     :ValueProfile,
     :ValueProfileAndOperandBuffer,
-    :ArithProfile,
+    :UnaryArithProfile,
+    :BinaryArithProfile,
     :ArrayProfile,
     :ArrayAllocationProfile,
     :ObjectAllocationProfile,
@@ -282,7 +284,7 @@
         operandTypes: OperandTypes,
     },
     metadata: {
-        arithProfile: ArithProfile
+        arithProfile: BinaryArithProfile
     },
     metadata_initializers: {
         arithProfile: :operandTypes
@@ -367,13 +369,13 @@
     args: {
         dst: VirtualRegister,
         operand: VirtualRegister,
-        operandTypes: OperandTypes,
+        resultType: ResultType,
     },
     metadata: {
-        arithProfile: ArithProfile,
+        arithProfile: UnaryArithProfile,
     },
     metadata_initializers: {
-        arithProfile: :operandTypes
+        arithProfile: :resultType
     }
 
 op :not,
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 60cc65e..143a362 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -1480,25 +1480,25 @@
     return ensureJITData(locker).m_stubInfos.add(accessType);
 }
 
-JITAddIC* CodeBlock::addJITAddIC(ArithProfile* arithProfile)
+JITAddIC* CodeBlock::addJITAddIC(BinaryArithProfile* arithProfile)
 {
     ConcurrentJSLocker locker(m_lock);
     return ensureJITData(locker).m_addICs.add(arithProfile);
 }
 
-JITMulIC* CodeBlock::addJITMulIC(ArithProfile* arithProfile)
+JITMulIC* CodeBlock::addJITMulIC(BinaryArithProfile* arithProfile)
 {
     ConcurrentJSLocker locker(m_lock);
     return ensureJITData(locker).m_mulICs.add(arithProfile);
 }
 
-JITSubIC* CodeBlock::addJITSubIC(ArithProfile* arithProfile)
+JITSubIC* CodeBlock::addJITSubIC(BinaryArithProfile* arithProfile)
 {
     ConcurrentJSLocker locker(m_lock);
     return ensureJITData(locker).m_subICs.add(arithProfile);
 }
 
-JITNegIC* CodeBlock::addJITNegIC(ArithProfile* arithProfile)
+JITNegIC* CodeBlock::addJITNegIC(UnaryArithProfile* arithProfile)
 {
     ConcurrentJSLocker locker(m_lock);
     return ensureJITData(locker).m_negICs.add(arithProfile);
@@ -3085,16 +3085,19 @@
     return instructions().at(offset + target).ptr();
 }
 
-ArithProfile* CodeBlock::arithProfileForBytecodeOffset(InstructionStream::Offset bytecodeOffset)
+BinaryArithProfile* CodeBlock::binaryArithProfileForBytecodeOffset(InstructionStream::Offset bytecodeOffset)
 {
-    return arithProfileForPC(instructions().at(bytecodeOffset).ptr());
+    return binaryArithProfileForPC(instructions().at(bytecodeOffset).ptr());
 }
 
-ArithProfile* CodeBlock::arithProfileForPC(const Instruction* pc)
+UnaryArithProfile* CodeBlock::unaryArithProfileForBytecodeOffset(InstructionStream::Offset bytecodeOffset)
+{
+    return unaryArithProfileForPC(instructions().at(bytecodeOffset).ptr());
+}
+
+BinaryArithProfile* CodeBlock::binaryArithProfileForPC(const Instruction* pc)
 {
     switch (pc->opcodeID()) {
-    case op_negate:
-        return &pc->as<OpNegate>().metadata(this).m_arithProfile;
     case op_add:
         return &pc->as<OpAdd>().metadata(this).m_arithProfile;
     case op_mul:
@@ -3110,11 +3113,23 @@
     return nullptr;
 }
 
+UnaryArithProfile* CodeBlock::unaryArithProfileForPC(const Instruction* pc)
+{
+    switch (pc->opcodeID()) {
+    case op_negate:
+        return &pc->as<OpNegate>().metadata(this).m_arithProfile;
+    default:
+        break;
+    }
+
+    return nullptr;
+}
+
 bool CodeBlock::couldTakeSpecialFastCase(InstructionStream::Offset bytecodeOffset)
 {
     if (!hasBaselineJITProfiling())
         return false;
-    ArithProfile* profile = arithProfileForBytecodeOffset(bytecodeOffset);
+    BinaryArithProfile* profile = binaryArithProfileForBytecodeOffset(bytecodeOffset);
     if (!profile)
         return false;
     return profile->tookSpecialFastPath();
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index 4233ea2..2a036ca 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -83,6 +83,8 @@
 } // namespace DFG
 #endif
 
+class UnaryArithProfile;
+class BinaryArithProfile;
 class BytecodeLivenessAnalysis;
 class CodeBlockSet;
 class ExecutableToCodeBlockEdge;
@@ -96,7 +98,6 @@
 
 enum class AccessType : int8_t;
 
-struct ArithProfile;
 struct OpCatch;
 
 enum ReoptimizationMode { DontCountReoptimization, CountReoptimization };
@@ -279,22 +280,22 @@
     }
     JITData& ensureJITDataSlow(const ConcurrentJSLocker&);
 
-    JITAddIC* addJITAddIC(ArithProfile*);
-    JITMulIC* addJITMulIC(ArithProfile*);
-    JITNegIC* addJITNegIC(ArithProfile*);
-    JITSubIC* addJITSubIC(ArithProfile*);
+    JITAddIC* addJITAddIC(BinaryArithProfile*);
+    JITMulIC* addJITMulIC(BinaryArithProfile*);
+    JITNegIC* addJITNegIC(UnaryArithProfile*);
+    JITSubIC* addJITSubIC(BinaryArithProfile*);
 
     template <typename Generator, typename = typename std::enable_if<std::is_same<Generator, JITAddGenerator>::value>::type>
-    JITAddIC* addMathIC(ArithProfile* profile) { return addJITAddIC(profile); }
+    JITAddIC* addMathIC(BinaryArithProfile* profile) { return addJITAddIC(profile); }
 
     template <typename Generator, typename = typename std::enable_if<std::is_same<Generator, JITMulGenerator>::value>::type>
-    JITMulIC* addMathIC(ArithProfile* profile) { return addJITMulIC(profile); }
+    JITMulIC* addMathIC(BinaryArithProfile* profile) { return addJITMulIC(profile); }
 
     template <typename Generator, typename = typename std::enable_if<std::is_same<Generator, JITNegGenerator>::value>::type>
-    JITNegIC* addMathIC(ArithProfile* profile) { return addJITNegIC(profile); }
+    JITNegIC* addMathIC(UnaryArithProfile* profile) { return addJITNegIC(profile); }
 
     template <typename Generator, typename = typename std::enable_if<std::is_same<Generator, JITSubGenerator>::value>::type>
-    JITSubIC* addMathIC(ArithProfile* profile) { return addJITSubIC(profile); }
+    JITSubIC* addMathIC(BinaryArithProfile* profile) { return addJITSubIC(profile); }
 
     StructureStubInfo* addStubInfo(AccessType);
 
@@ -492,8 +493,10 @@
     template<typename Functor> void forEachObjectAllocationProfile(const Functor&);
     template<typename Functor> void forEachLLIntCallLinkInfo(const Functor&);
 
-    ArithProfile* arithProfileForBytecodeOffset(InstructionStream::Offset bytecodeOffset);
-    ArithProfile* arithProfileForPC(const Instruction*);
+    BinaryArithProfile* binaryArithProfileForBytecodeOffset(InstructionStream::Offset bytecodeOffset);
+    UnaryArithProfile* unaryArithProfileForBytecodeOffset(InstructionStream::Offset bytecodeOffset);
+    BinaryArithProfile* binaryArithProfileForPC(const Instruction*);
+    UnaryArithProfile* unaryArithProfileForPC(const Instruction*);
 
     bool couldTakeSpecialFastCase(InstructionStream::Offset bytecodeOffset);
 
diff --git a/Source/JavaScriptCore/bytecode/Fits.h b/Source/JavaScriptCore/bytecode/Fits.h
index 9ab7713..77794c7 100644
--- a/Source/JavaScriptCore/bytecode/Fits.h
+++ b/Source/JavaScriptCore/bytecode/Fits.h
@@ -237,6 +237,27 @@
 };
 
 template<OpcodeSize size>
+struct Fits<ResultType, size, std::enable_if_t<sizeof(ResultType) != size, std::true_type>> {
+    static_assert(sizeof(ResultType) == sizeof(uint8_t));
+    using TargetType = typename TypeBySize<size>::unsignedType;
+
+    static bool check(ResultType)
+    {
+        return true;
+    }
+
+    static TargetType convert(ResultType type)
+    {
+        return static_cast<TargetType>(type.bits());
+    }
+
+    static ResultType convert(TargetType type)
+    {
+        return ResultType(static_cast<uint8_t>(type));
+    }
+};
+
+template<OpcodeSize size>
 struct Fits<OperandTypes, size, std::enable_if_t<sizeof(OperandTypes) != size, std::true_type>> {
     static_assert(sizeof(OperandTypes) == sizeof(uint16_t));
     using TargetType = typename TypeBySize<size>::unsignedType;
diff --git a/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp b/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp
index 7e3cc94..e027769 100644
--- a/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp
+++ b/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp
@@ -66,10 +66,16 @@
         return;
     }
         
-    case ArithProfileReady: {
-        u.arithProfile->emitObserveResult(jit, regs, DoNotHaveTagRegisters);
+    case UnaryArithProfileReady: {
+        u.unaryArithProfile->emitObserveResult(jit, regs, DoNotHaveTagRegisters);
         return;
-    } }
+    }
+
+    case BinaryArithProfileReady: {
+        u.binaryArithProfile->emitObserveResult(jit, regs, DoNotHaveTagRegisters);
+        return;
+    }
+    }
     
     RELEASE_ASSERT_NOT_REACHED();
 }
@@ -94,10 +100,16 @@
         return;
     }
 
-    case ArithProfileReady: {
-        u.arithProfile->observeResult(value);
+    case UnaryArithProfileReady: {
+        u.unaryArithProfile->observeResult(value);
         return;
-    } }
+    }
+
+    case BinaryArithProfileReady: {
+        u.binaryArithProfile->observeResult(value);
+        return;
+    }
+    }
 
     RELEASE_ASSERT_NOT_REACHED();
 }
diff --git a/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h b/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h
index b5e84b1..0441501 100644
--- a/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h
+++ b/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h
@@ -35,10 +35,11 @@
 
 namespace JSC {
 
+class UnaryArithProfile;
+class BinaryArithProfile;
 class CCallHelpers;
 class CodeBlock;
 class LazyOperandValueProfileKey;
-struct ArithProfile;
 struct ValueProfile;
 
 class MethodOfGettingAValueProfile {
@@ -56,12 +57,21 @@
         } else
             m_kind = None;
     }
-    
-    MethodOfGettingAValueProfile(ArithProfile* profile)
+
+    MethodOfGettingAValueProfile(UnaryArithProfile* profile)
     {
         if (profile) {
-            m_kind = ArithProfileReady;
-            u.arithProfile = profile;
+            m_kind = UnaryArithProfileReady;
+            u.unaryArithProfile = profile;
+        } else
+            m_kind = None;
+    }
+
+    MethodOfGettingAValueProfile(BinaryArithProfile* profile)
+    {
+        if (profile) {
+            m_kind = BinaryArithProfileReady;
+            u.binaryArithProfile = profile;
         } else
             m_kind = None;
     }
@@ -78,14 +88,16 @@
     enum Kind {
         None,
         Ready,
-        ArithProfileReady,
+        UnaryArithProfileReady,
+        BinaryArithProfileReady,
         LazyOperand
     };
     
     Kind m_kind;
     union {
         ValueProfile* profile;
-        ArithProfile* arithProfile;
+        UnaryArithProfile* unaryArithProfile;
+        BinaryArithProfile* binaryArithProfile;
         struct {
             CodeBlock* codeBlock;
             unsigned bytecodeOffset;
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
index e7914aa..b7a4aa3 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
@@ -1665,14 +1665,14 @@
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src, OperandTypes types)
+RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src, ResultType type)
 {
     switch (opcodeID) {
     case op_not:
         emitUnaryOp<OpNot>(dst, src);
         break;
     case op_negate:
-        OpNegate::emit(this, dst, src, types);
+        OpNegate::emit(this, dst, src, type);
         break;
     case op_bitnot:
         emitUnaryOp<OpBitnot>(dst, src);
diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
index 4197abc..38e77cd 100644
--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
@@ -682,7 +682,7 @@
             return dst;
         }
 
-        RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src, OperandTypes);
+        RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src, ResultType);
 
         template<typename BinaryOp>
         std::enable_if_t<
diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
index 65937f3..e481a4f 100644
--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
@@ -2136,7 +2136,7 @@
 {
     RefPtr<RegisterID> src = generator.emitNode(m_expr);
     generator.emitExpressionInfo(position(), position(), position());
-    return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src.get(), OperandTypes(m_expr->resultDescriptor()));
+    return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src.get(), m_expr->resultDescriptor());
 }
 
 // ------------------------------ UnaryPlusNode -----------------------------------
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 661013a..1fe4dbe 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -942,56 +942,60 @@
         if (!isX86() && (node->op() == ArithMod || node->op() == ValueMod))
             return node;
 
-        {
-            ArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->arithProfileForBytecodeOffset(m_currentIndex);
-            if (arithProfile) {
-                switch (node->op()) {
-                case ArithAdd:
-                case ArithSub:
-                case ValueAdd:
-                    if (arithProfile->didObserveDouble())
-                        node->mergeFlags(NodeMayHaveDoubleResult);
-                    if (arithProfile->didObserveNonNumeric())
-                        node->mergeFlags(NodeMayHaveNonNumericResult);
-                    if (arithProfile->didObserveBigInt())
-                        node->mergeFlags(NodeMayHaveBigIntResult);
-                    break;
-                
-                case ValueMul:
-                case ArithMul: {
-                    if (arithProfile->didObserveInt52Overflow())
-                        node->mergeFlags(NodeMayOverflowInt52);
-                    if (arithProfile->didObserveInt32Overflow() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
-                        node->mergeFlags(NodeMayOverflowInt32InBaseline);
-                    if (arithProfile->didObserveNegZeroDouble() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
-                        node->mergeFlags(NodeMayNegZeroInBaseline);
-                    if (arithProfile->didObserveDouble())
-                        node->mergeFlags(NodeMayHaveDoubleResult);
-                    if (arithProfile->didObserveNonNumeric())
-                        node->mergeFlags(NodeMayHaveNonNumericResult);
-                    if (arithProfile->didObserveBigInt())
-                        node->mergeFlags(NodeMayHaveBigIntResult);
-                    break;
-                }
-                case ValueNegate:
-                case ArithNegate: {
-                    if (arithProfile->lhsObservedType().sawNumber() || arithProfile->didObserveDouble())
-                        node->mergeFlags(NodeMayHaveDoubleResult);
-                    if (arithProfile->didObserveNegZeroDouble() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
-                        node->mergeFlags(NodeMayNegZeroInBaseline);
-                    if (arithProfile->didObserveInt32Overflow() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
-                        node->mergeFlags(NodeMayOverflowInt32InBaseline);
-                    if (arithProfile->didObserveNonNumeric())
-                        node->mergeFlags(NodeMayHaveNonNumericResult);
-                    if (arithProfile->didObserveBigInt())
-                        node->mergeFlags(NodeMayHaveBigIntResult);
-                    break;
-                }
-                
-                default:
-                    break;
-                }
-            }
+        switch (node->op()) {
+        case ArithAdd:
+        case ArithSub:
+        case ValueAdd: {
+            BinaryArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->binaryArithProfileForBytecodeOffset(m_currentIndex);
+            if (!arithProfile)
+                break;
+            if (arithProfile->didObserveDouble())
+                node->mergeFlags(NodeMayHaveDoubleResult);
+            if (arithProfile->didObserveNonNumeric())
+                node->mergeFlags(NodeMayHaveNonNumericResult);
+            if (arithProfile->didObserveBigInt())
+                node->mergeFlags(NodeMayHaveBigIntResult);
+            break;
+        }
+        case ValueMul:
+        case ArithMul: {
+            BinaryArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->binaryArithProfileForBytecodeOffset(m_currentIndex);
+            if (!arithProfile)
+                break;
+            if (arithProfile->didObserveInt52Overflow())
+                node->mergeFlags(NodeMayOverflowInt52);
+            if (arithProfile->didObserveInt32Overflow() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
+                node->mergeFlags(NodeMayOverflowInt32InBaseline);
+            if (arithProfile->didObserveNegZeroDouble() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
+                node->mergeFlags(NodeMayNegZeroInBaseline);
+            if (arithProfile->didObserveDouble())
+                node->mergeFlags(NodeMayHaveDoubleResult);
+            if (arithProfile->didObserveNonNumeric())
+                node->mergeFlags(NodeMayHaveNonNumericResult);
+            if (arithProfile->didObserveBigInt())
+                node->mergeFlags(NodeMayHaveBigIntResult);
+            break;
+        }
+        case ValueNegate:
+        case ArithNegate: {
+            UnaryArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->unaryArithProfileForBytecodeOffset(m_currentIndex);
+            if (!arithProfile)
+                break;
+            if (arithProfile->argObservedType().sawNumber() || arithProfile->didObserveDouble())
+                node->mergeFlags(NodeMayHaveDoubleResult);
+            if (arithProfile->didObserveNegZeroDouble() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero))
+                node->mergeFlags(NodeMayNegZeroInBaseline);
+            if (arithProfile->didObserveInt32Overflow() || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))
+                node->mergeFlags(NodeMayOverflowInt32InBaseline);
+            if (arithProfile->didObserveNonNumeric())
+                node->mergeFlags(NodeMayHaveNonNumericResult);
+            if (arithProfile->didObserveBigInt())
+                node->mergeFlags(NodeMayHaveBigIntResult);
+            break;
+        }
+
+        default:
+            break;
         }
         
         if (m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)) {
@@ -1034,7 +1038,7 @@
         // FIXME: It might be possible to make this more granular.
         node->mergeFlags(NodeMayOverflowInt32InBaseline | NodeMayNegZeroInBaseline);
         
-        ArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->arithProfileForBytecodeOffset(m_currentIndex);
+        BinaryArithProfile* arithProfile = m_inlineStackTop->m_profiledBlock->binaryArithProfileForBytecodeOffset(m_currentIndex);
         if (arithProfile->didObserveBigInt())
             node->mergeFlags(NodeMayHaveBigIntResult);
 
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index 9d5b7d9..4c6d109 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -1652,7 +1652,9 @@
                 return &profiledBlock->valueProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex());
 
             if (profiledBlock->hasBaselineJITProfiling()) {
-                if (ArithProfile* result = profiledBlock->arithProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex()))
+                if (BinaryArithProfile* result = profiledBlock->binaryArithProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex()))
+                    return result;
+                if (UnaryArithProfile* result = profiledBlock->unaryArithProfileForBytecodeOffset(node->origin.semantic.bytecodeIndex()))
                     return result;
             }
         }
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 9d038b5..f632d11 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -4000,7 +4000,7 @@
 
     CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
     unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
-    ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
+    BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeOffset(bytecodeIndex);
     JITAddIC* addIC = m_jit.codeBlock()->addJITAddIC(arithProfile);
     auto repatchingFunction = operationValueAddOptimize;
     auto nonRepatchingFunction = operationValueAdd;
@@ -4024,7 +4024,7 @@
 
         CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
         unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
-        ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
+        BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeOffset(bytecodeIndex);
         JITSubIC* subIC = m_jit.codeBlock()->addJITSubIC(arithProfile);
         auto repatchingFunction = operationValueSubOptimize;
         auto nonRepatchingFunction = operationValueSub;
@@ -4618,7 +4618,7 @@
 {
     CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
     unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
-    ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
+    UnaryArithProfile* arithProfile = baselineCodeBlock->unaryArithProfileForBytecodeOffset(bytecodeIndex);
     JITNegIC* negIC = m_jit.codeBlock()->addJITNegIC(arithProfile);
     auto repatchingFunction = operationArithNegateOptimize;
     auto nonRepatchingFunction = operationArithNegate;
@@ -4841,7 +4841,7 @@
 
     CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
     unsigned bytecodeIndex = node->origin.semantic.bytecodeIndex();
-    ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
+    BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeOffset(bytecodeIndex);
     JITMulIC* mulIC = m_jit.codeBlock()->addJITMulIC(arithProfile);
     auto repatchingFunction = operationValueMulOptimize;
     auto nonRepatchingFunction = operationValueMul;
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
index a3b84d6..938dc87 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
@@ -2107,7 +2107,7 @@
 
         CodeBlock* baselineCodeBlock = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic);
         unsigned bytecodeIndex = m_node->origin.semantic.bytecodeIndex();
-        ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
+        BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeOffset(bytecodeIndex);
         auto repatchingFunction = operationValueAddOptimize;
         auto nonRepatchingFunction = operationValueAdd;
         compileBinaryMathIC<JITAddGenerator>(arithProfile, repatchingFunction, nonRepatchingFunction);
@@ -2126,7 +2126,7 @@
 
         CodeBlock* baselineCodeBlock = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic);
         unsigned bytecodeIndex = m_node->origin.semantic.bytecodeIndex();
-        ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
+        BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeOffset(bytecodeIndex);
         auto repatchingFunction = operationValueSubOptimize;
         auto nonRepatchingFunction = operationValueSub;
         compileBinaryMathIC<JITSubGenerator>(arithProfile, repatchingFunction, nonRepatchingFunction);
@@ -2145,7 +2145,7 @@
 
         CodeBlock* baselineCodeBlock = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic);
         unsigned bytecodeIndex = m_node->origin.semantic.bytecodeIndex();
-        ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
+        BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeOffset(bytecodeIndex);
         auto repatchingFunction = operationValueMulOptimize;
         auto nonRepatchingFunction = operationValueMul;
         compileBinaryMathIC<JITMulGenerator>(arithProfile, repatchingFunction, nonRepatchingFunction);
@@ -2153,7 +2153,7 @@
 
     template <typename Generator, typename Func1, typename Func2,
         typename = std::enable_if_t<std::is_function<typename std::remove_pointer<Func1>::type>::value && std::is_function<typename std::remove_pointer<Func2>::type>::value>>
-    void compileUnaryMathIC(ArithProfile* arithProfile, Func1 repatchingFunction, Func2 nonRepatchingFunction)
+    void compileUnaryMathIC(UnaryArithProfile* arithProfile, Func1 repatchingFunction, Func2 nonRepatchingFunction)
     {
         Node* node = m_node;
 
@@ -2239,7 +2239,7 @@
 
     template <typename Generator, typename Func1, typename Func2,
         typename = std::enable_if_t<std::is_function<typename std::remove_pointer<Func1>::type>::value && std::is_function<typename std::remove_pointer<Func2>::type>::value>>
-    void compileBinaryMathIC(ArithProfile* arithProfile, Func1 repatchingFunction, Func2 nonRepatchingFunction)
+    void compileBinaryMathIC(BinaryArithProfile* arithProfile, Func1 repatchingFunction, Func2 nonRepatchingFunction)
     {
         Node* node = m_node;
         
@@ -2406,7 +2406,7 @@
 
             CodeBlock* baselineCodeBlock = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic);
             unsigned bytecodeIndex = m_node->origin.semantic.bytecodeIndex();
-            ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
+            BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeOffset(bytecodeIndex);
             auto repatchingFunction = operationValueSubOptimize;
             auto nonRepatchingFunction = operationValueSub;
             compileBinaryMathIC<JITSubGenerator>(arithProfile, repatchingFunction, nonRepatchingFunction);
@@ -3072,7 +3072,7 @@
         DFG_ASSERT(m_graph, m_node, m_node->child1().useKind() == UntypedUse);
         CodeBlock* baselineCodeBlock = m_ftlState.graph.baselineCodeBlockFor(m_node->origin.semantic);
         unsigned bytecodeIndex = m_node->origin.semantic.bytecodeIndex();
-        ArithProfile* arithProfile = baselineCodeBlock->arithProfileForBytecodeOffset(bytecodeIndex);
+        UnaryArithProfile* arithProfile = baselineCodeBlock->unaryArithProfileForBytecodeOffset(bytecodeIndex);
         auto repatchingFunction = operationArithNegateOptimize;
         auto nonRepatchingFunction = operationArithNegate;
         compileUnaryMathIC<JITNegGenerator>(arithProfile, repatchingFunction, nonRepatchingFunction);
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index 427e9ae..0d22fd0 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -919,7 +919,7 @@
         // It will give the slow path the same value read by the fast path.
         GetPutInfo copiedGetPutInfo(OpPutToScope);
         template<typename BinaryOp>
-        ArithProfile copiedArithProfile(BinaryOp);
+        BinaryArithProfile copiedArithProfile(BinaryOp);
 
         Interpreter* m_interpreter;
 
@@ -939,7 +939,7 @@
         Vector<SwitchRecord> m_switches;
 
         HashMap<unsigned, unsigned> m_copiedGetPutInfos;
-        HashMap<uint64_t, ArithProfile> m_copiedArithProfiles;
+        HashMap<uint64_t, BinaryArithProfile> m_copiedArithProfiles;
 
         JumpList m_exceptionChecks;
         JumpList m_exceptionChecksWithCallFrameRollback;
diff --git a/Source/JavaScriptCore/jit/JITAddGenerator.cpp b/Source/JavaScriptCore/jit/JITAddGenerator.cpp
index 627af27..740b2ed 100644
--- a/Source/JavaScriptCore/jit/JITAddGenerator.cpp
+++ b/Source/JavaScriptCore/jit/JITAddGenerator.cpp
@@ -34,7 +34,7 @@
 
 namespace JSC {
 
-JITMathICInlineResult JITAddGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const ArithProfile* arithProfile)
+JITMathICInlineResult JITAddGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const BinaryArithProfile* arithProfile)
 {
     // We default to speculating int32.
     ObservedType lhs = ObservedType().withInt32();
@@ -73,7 +73,7 @@
     return JITMathICInlineResult::GenerateFullSnippet;
 }
 
-bool JITAddGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const ArithProfile* arithProfile, bool shouldEmitProfiling)
+bool JITAddGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const BinaryArithProfile* arithProfile, bool shouldEmitProfiling)
 {
     ASSERT(m_scratchGPR != InvalidGPRReg);
     ASSERT(m_scratchGPR != m_left.payloadGPR());
diff --git a/Source/JavaScriptCore/jit/JITAddGenerator.h b/Source/JavaScriptCore/jit/JITAddGenerator.h
index 4dc34a2..675cf93 100644
--- a/Source/JavaScriptCore/jit/JITAddGenerator.h
+++ b/Source/JavaScriptCore/jit/JITAddGenerator.h
@@ -55,8 +55,8 @@
         ASSERT(!m_leftOperand.isConstInt32() || !m_rightOperand.isConstInt32());
     }
 
-    JITMathICInlineResult generateInline(CCallHelpers&, MathICGenerationState&, const ArithProfile*);
-    bool generateFastPath(CCallHelpers&, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const ArithProfile*, bool shouldEmitProfiling);
+    JITMathICInlineResult generateInline(CCallHelpers&, MathICGenerationState&, const BinaryArithProfile*);
+    bool generateFastPath(CCallHelpers&, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const BinaryArithProfile*, bool shouldEmitProfiling);
 
     static bool isLeftOperandValidConstant(SnippetOperand leftOperand) { return leftOperand.isPositiveConstInt32(); }
     static bool isRightOperandValidConstant(SnippetOperand rightOperand) { return rightOperand.isPositiveConstInt32(); }
diff --git a/Source/JavaScriptCore/jit/JITArithmetic.cpp b/Source/JavaScriptCore/jit/JITArithmetic.cpp
index f420ae9..67f9986 100644
--- a/Source/JavaScriptCore/jit/JITArithmetic.cpp
+++ b/Source/JavaScriptCore/jit/JITArithmetic.cpp
@@ -452,7 +452,7 @@
 
 void JIT::emit_op_negate(const Instruction* currentInstruction)
 {
-    ArithProfile* arithProfile = &currentInstruction->as<OpNegate>().metadata(m_codeBlock).m_arithProfile;
+    UnaryArithProfile* arithProfile = &currentInstruction->as<OpNegate>().metadata(m_codeBlock).m_arithProfile;
     JITNegIC* negateIC = m_codeBlock->addJITNegIC(arithProfile);
     m_instructionToMathIC.add(currentInstruction, negateIC);
     emitMathICFast<OpNegate>(negateIC, currentInstruction, operationArithNegateProfiled, operationArithNegate);
@@ -633,14 +633,9 @@
     emitRightShiftFastPath(currentInstruction, op_urshift);
 }
 
-ALWAYS_INLINE static OperandTypes getOperandTypes(const ArithProfile& arithProfile)
-{
-    return OperandTypes(arithProfile.lhsResultType(), arithProfile.rhsResultType());
-}
-
 void JIT::emit_op_add(const Instruction* currentInstruction)
 {
-    ArithProfile* arithProfile = &currentInstruction->as<OpAdd>().metadata(m_codeBlock).m_arithProfile;
+    BinaryArithProfile* arithProfile = &currentInstruction->as<OpAdd>().metadata(m_codeBlock).m_arithProfile;
     JITAddIC* addIC = m_codeBlock->addJITAddIC(arithProfile);
     m_instructionToMathIC.add(currentInstruction, addIC);
     emitMathICFast<OpAdd>(addIC, currentInstruction, operationValueAddProfiled, operationValueAdd);
@@ -685,7 +680,7 @@
 
     bool generatedInlineCode = mathIC->generateInline(*this, mathICGenerationState);
     if (!generatedInlineCode) {
-        ArithProfile* arithProfile = mathIC->arithProfile();
+        UnaryArithProfile* arithProfile = mathIC->arithProfile();
         if (arithProfile && shouldEmitProfiling())
             callOperationWithResult(profiledFunction, resultRegs, srcRegs, arithProfile);
         else
@@ -708,7 +703,7 @@
 void JIT::emitMathICFast(JITBinaryMathIC<Generator>* mathIC, const Instruction* currentInstruction, ProfiledFunction profiledFunction, NonProfiledFunction nonProfiledFunction)
 {
     auto bytecode = currentInstruction->as<Op>();
-    OperandTypes types = getOperandTypes(copiedArithProfile(bytecode));
+    BinaryArithProfile arithProfile = copiedArithProfile(bytecode);
     int result = bytecode.m_dst.offset();
     int op1 = bytecode.m_lhs.offset();
     int op2 = bytecode.m_rhs.offset();
@@ -727,8 +722,8 @@
     FPRReg scratchFPR = fpRegT2;
 #endif
 
-    SnippetOperand leftOperand(types.first());
-    SnippetOperand rightOperand(types.second());
+    SnippetOperand leftOperand(arithProfile.lhsResultType());
+    SnippetOperand rightOperand(arithProfile.rhsResultType());
 
     if (isOperandConstantInt(op1))
         leftOperand.setConstInt32(getOperandConstantInt(op1));
@@ -758,7 +753,7 @@
             emitGetVirtualRegister(op1, leftRegs);
         else if (rightOperand.isConst())
             emitGetVirtualRegister(op2, rightRegs);
-        ArithProfile* arithProfile = mathIC->arithProfile();
+        BinaryArithProfile* arithProfile = mathIC->arithProfile();
         if (arithProfile && shouldEmitProfiling())
             callOperationWithResult(profiledFunction, resultRegs, leftRegs, rightRegs, arithProfile);
         else
@@ -798,7 +793,7 @@
     auto slowPathStart = label();
 #endif
 
-    ArithProfile* arithProfile = mathIC->arithProfile();
+    UnaryArithProfile* arithProfile = mathIC->arithProfile();
     if (arithProfile && shouldEmitProfiling()) {
         if (mathICGenerationState.shouldSlowPathRepatch)
             mathICGenerationState.slowPathCall = callOperationWithResult(reinterpret_cast<J_JITOperation_EJMic>(profiledRepatchFunction), resultRegs, srcRegs, TrustedImmPtr(mathIC));
@@ -830,7 +825,7 @@
     mathICGenerationState.slowPathStart = label();
 
     auto bytecode = currentInstruction->as<Op>();
-    OperandTypes types = getOperandTypes(copiedArithProfile(bytecode));
+    BinaryArithProfile consistentArithProfile = copiedArithProfile(bytecode);
     int result = bytecode.m_dst.offset();
     int op1 = bytecode.m_lhs.offset();
     int op2 = bytecode.m_rhs.offset();
@@ -845,8 +840,8 @@
     JSValueRegs resultRegs = leftRegs;
 #endif
     
-    SnippetOperand leftOperand(types.first());
-    SnippetOperand rightOperand(types.second());
+    SnippetOperand leftOperand(consistentArithProfile.lhsResultType());
+    SnippetOperand rightOperand(consistentArithProfile.rhsResultType());
 
     if (isOperandConstantInt(op1))
         leftOperand.setConstInt32(getOperandConstantInt(op1));
@@ -864,7 +859,7 @@
     auto slowPathStart = label();
 #endif
 
-    ArithProfile* arithProfile = mathIC->arithProfile();
+    BinaryArithProfile* arithProfile = mathIC->arithProfile();
     if (arithProfile && shouldEmitProfiling()) {
         if (mathICGenerationState.shouldSlowPathRepatch)
             mathICGenerationState.slowPathCall = callOperationWithResult(bitwise_cast<J_JITOperation_EJJMic>(profiledRepatchFunction), resultRegs, leftRegs, rightRegs, TrustedImmPtr(mathIC));
@@ -892,19 +887,17 @@
 void JIT::emit_op_div(const Instruction* currentInstruction)
 {
     auto bytecode = currentInstruction->as<OpDiv>();
-    auto& metadata = bytecode.metadata(m_codeBlock);
+    BinaryArithProfile consistentArithProfile = copiedArithProfile(bytecode);
     int result = bytecode.m_dst.offset();
     int op1 = bytecode.m_lhs.offset();
     int op2 = bytecode.m_rhs.offset();
 
 #if USE(JSVALUE64)
-    OperandTypes types = getOperandTypes(metadata.m_arithProfile);
     JSValueRegs leftRegs = JSValueRegs(regT0);
     JSValueRegs rightRegs = JSValueRegs(regT1);
     JSValueRegs resultRegs = leftRegs;
     GPRReg scratchGPR = regT2;
 #else
-    OperandTypes types = getOperandTypes(metadata.m_arithProfile);
     JSValueRegs leftRegs = JSValueRegs(regT1, regT0);
     JSValueRegs rightRegs = JSValueRegs(regT3, regT2);
     JSValueRegs resultRegs = leftRegs;
@@ -912,12 +905,12 @@
 #endif
     FPRReg scratchFPR = fpRegT2;
 
-    ArithProfile* arithProfile = nullptr;
+    BinaryArithProfile* arithProfile = nullptr;
     if (shouldEmitProfiling())
         arithProfile = &currentInstruction->as<OpDiv>().metadata(m_codeBlock).m_arithProfile;
 
-    SnippetOperand leftOperand(types.first());
-    SnippetOperand rightOperand(types.second());
+    SnippetOperand leftOperand(consistentArithProfile.lhsResultType());
+    SnippetOperand rightOperand(consistentArithProfile.rhsResultType());
 
     if (isOperandConstantInt(op1))
         leftOperand.setConstInt32(getOperandConstantInt(op1));
@@ -959,7 +952,7 @@
 
 void JIT::emit_op_mul(const Instruction* currentInstruction)
 {
-    ArithProfile* arithProfile = &currentInstruction->as<OpMul>().metadata(m_codeBlock).m_arithProfile;
+    BinaryArithProfile* arithProfile = &currentInstruction->as<OpMul>().metadata(m_codeBlock).m_arithProfile;
     JITMulIC* mulIC = m_codeBlock->addJITMulIC(arithProfile);
     m_instructionToMathIC.add(currentInstruction, mulIC);
     emitMathICFast<OpMul>(mulIC, currentInstruction, operationValueMulProfiled, operationValueMul);
@@ -975,7 +968,7 @@
 
 void JIT::emit_op_sub(const Instruction* currentInstruction)
 {
-    ArithProfile* arithProfile = &currentInstruction->as<OpSub>().metadata(m_codeBlock).m_arithProfile;
+    BinaryArithProfile* arithProfile = &currentInstruction->as<OpSub>().metadata(m_codeBlock).m_arithProfile;
     JITSubIC* subIC = m_codeBlock->addJITSubIC(arithProfile);
     m_instructionToMathIC.add(currentInstruction, subIC);
     emitMathICFast<OpSub>(subIC, currentInstruction, operationValueSubProfiled, operationValueSub);
diff --git a/Source/JavaScriptCore/jit/JITDivGenerator.cpp b/Source/JavaScriptCore/jit/JITDivGenerator.cpp
index 66e1be1..b8c4798 100644
--- a/Source/JavaScriptCore/jit/JITDivGenerator.cpp
+++ b/Source/JavaScriptCore/jit/JITDivGenerator.cpp
@@ -130,7 +130,7 @@
     notDoubleZero.link(&jit);
 #endif
     if (m_arithProfile)
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::specialFastPathBit), CCallHelpers::AbsoluteAddress(m_arithProfile->addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(BinaryArithProfile::specialFastPathBit), CCallHelpers::AbsoluteAddress(m_arithProfile->addressOfBits()));
     jit.boxDouble(m_leftFPR, m_result);
 }
 
diff --git a/Source/JavaScriptCore/jit/JITDivGenerator.h b/Source/JavaScriptCore/jit/JITDivGenerator.h
index 8396677..708db10 100644
--- a/Source/JavaScriptCore/jit/JITDivGenerator.h
+++ b/Source/JavaScriptCore/jit/JITDivGenerator.h
@@ -37,7 +37,7 @@
     JITDivGenerator(SnippetOperand leftOperand, SnippetOperand rightOperand,
         JSValueRegs result, JSValueRegs left, JSValueRegs right,
         FPRReg leftFPR, FPRReg rightFPR, GPRReg scratchGPR, FPRReg scratchFPR,
-        ArithProfile* arithProfile = nullptr)
+        BinaryArithProfile* arithProfile = nullptr)
         : m_leftOperand(leftOperand)
         , m_rightOperand(rightOperand)
         , m_result(result)
@@ -71,7 +71,7 @@
     GPRReg m_scratchGPR;
     FPRReg m_scratchFPR;
     bool m_didEmitFastPath { false };
-    ArithProfile* m_arithProfile;
+    BinaryArithProfile* m_arithProfile;
 
     CCallHelpers::JumpList m_endJumpList;
     CCallHelpers::JumpList m_slowPathJumpList;
diff --git a/Source/JavaScriptCore/jit/JITInlines.h b/Source/JavaScriptCore/jit/JITInlines.h
index 3959b8d..57a81ec 100644
--- a/Source/JavaScriptCore/jit/JITInlines.h
+++ b/Source/JavaScriptCore/jit/JITInlines.h
@@ -717,13 +717,13 @@
 }
 
 template<typename BinaryOp>
-ALWAYS_INLINE ArithProfile JIT::copiedArithProfile(BinaryOp bytecode)
+ALWAYS_INLINE BinaryArithProfile JIT::copiedArithProfile(BinaryOp bytecode)
 {
     uint64_t key = (static_cast<uint64_t>(BinaryOp::opcodeID) + 1) << 32 | static_cast<uint64_t>(bytecode.m_metadataID);
     auto iterator = m_copiedArithProfiles.find(key);
     if (iterator != m_copiedArithProfiles.end())
         return iterator->value;
-    ArithProfile arithProfile = bytecode.metadata(m_codeBlock).m_arithProfile;
+    BinaryArithProfile arithProfile = bytecode.metadata(m_codeBlock).m_arithProfile;
     m_copiedArithProfiles.add(key, arithProfile);
     return arithProfile;
 }
diff --git a/Source/JavaScriptCore/jit/JITMathIC.h b/Source/JavaScriptCore/jit/JITMathIC.h
index 5645e42..8464622 100644
--- a/Source/JavaScriptCore/jit/JITMathIC.h
+++ b/Source/JavaScriptCore/jit/JITMathIC.h
@@ -52,11 +52,11 @@
 
 #define ENABLE_MATH_IC_STATS 0
 
-template <typename GeneratorType, bool(*isProfileEmpty)(ArithProfile&)>
+template <typename GeneratorType, typename ArithProfileType>
 class JITMathIC {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    JITMathIC(ArithProfile* arithProfile)
+    JITMathIC(ArithProfileType* arithProfile)
         : m_arithProfile(arithProfile)
     {
     }
@@ -71,7 +71,7 @@
         size_t startSize = jit.m_assembler.buffer().codeSize();
 
         if (m_arithProfile) {
-            if (isProfileEmpty(*m_arithProfile)) {
+            if (m_arithProfile->isObservedTypeEmpty()) {
                 // It looks like the MathIC has yet to execute. We don't want to emit code in this
                 // case for a couple reasons. First, the operation may never execute, so if we don't emit
                 // code, it's a win. Second, if the operation does execute, we can emit better code
@@ -223,7 +223,7 @@
         m_slowPathStartLocation = linkBuffer.locationOf<JSInternalPtrTag>(state.slowPathStart);
     }
 
-    ArithProfile* arithProfile() const { return m_arithProfile; }
+    ArithProfileType* arithProfile() const { return m_arithProfile; }
 
 #if ENABLE(MATH_IC_STATS)
     size_t m_generatedCodeSize { 0 };
@@ -236,7 +236,7 @@
     }
 #endif
 
-    ArithProfile* m_arithProfile;
+    ArithProfileType* m_arithProfile;
     MacroAssemblerCodeRef<JITStubRoutinePtrTag> m_code;
     CodeLocationLabel<JSInternalPtrTag> m_inlineStart;
     CodeLocationLabel<JSInternalPtrTag> m_inlineEnd;
@@ -246,15 +246,15 @@
     GeneratorType m_generator;
 };
 
-inline bool isBinaryProfileEmpty(ArithProfile& arithProfile)
+inline bool isBinaryProfileEmpty(BinaryArithProfile& arithProfile)
 {
     return arithProfile.lhsObservedType().isEmpty() || arithProfile.rhsObservedType().isEmpty();
 }
 template <typename GeneratorType>
-class JITBinaryMathIC : public JITMathIC<GeneratorType, isBinaryProfileEmpty> {
+class JITBinaryMathIC : public JITMathIC<GeneratorType, BinaryArithProfile> {
 public:
-    JITBinaryMathIC(ArithProfile* arithProfile)
-        : JITMathIC<GeneratorType, isBinaryProfileEmpty>(arithProfile)
+    JITBinaryMathIC(BinaryArithProfile* arithProfile)
+        : JITMathIC<GeneratorType, BinaryArithProfile>(arithProfile)
     {
     }
 };
@@ -264,15 +264,15 @@
 typedef JITBinaryMathIC<JITSubGenerator> JITSubIC;
 
 
-inline bool isUnaryProfileEmpty(ArithProfile& arithProfile)
+inline bool isUnaryProfileEmpty(BinaryArithProfile& arithProfile)
 {
     return arithProfile.lhsObservedType().isEmpty();
 }
 template <typename GeneratorType>
-class JITUnaryMathIC : public JITMathIC<GeneratorType, isUnaryProfileEmpty> {
+class JITUnaryMathIC : public JITMathIC<GeneratorType, UnaryArithProfile> {
 public:
-    JITUnaryMathIC(ArithProfile* arithProfile)
-        : JITMathIC<GeneratorType, isUnaryProfileEmpty>(arithProfile)
+    JITUnaryMathIC(UnaryArithProfile* arithProfile)
+        : JITMathIC<GeneratorType, UnaryArithProfile>(arithProfile)
     {
     }
 };
diff --git a/Source/JavaScriptCore/jit/JITMulGenerator.cpp b/Source/JavaScriptCore/jit/JITMulGenerator.cpp
index 83d293b..cf6baa5 100644
--- a/Source/JavaScriptCore/jit/JITMulGenerator.cpp
+++ b/Source/JavaScriptCore/jit/JITMulGenerator.cpp
@@ -33,7 +33,7 @@
 
 namespace JSC {
 
-JITMathICInlineResult JITMulGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const ArithProfile* arithProfile)
+JITMathICInlineResult JITMulGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const BinaryArithProfile* arithProfile)
 {
     // We default to speculating int32.
     ObservedType lhs = ObservedType().withInt32();
@@ -89,7 +89,7 @@
     return JITMathICInlineResult::GenerateFullSnippet;
 }
 
-bool JITMulGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const ArithProfile* arithProfile, bool shouldEmitProfiling)
+bool JITMulGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const BinaryArithProfile* arithProfile, bool shouldEmitProfiling)
 {
     ASSERT(m_scratchGPR != InvalidGPRReg);
     ASSERT(m_scratchGPR != m_left.payloadGPR());
@@ -205,18 +205,18 @@
 
         CCallHelpers::Jump notNegativeZero = jit.branch64(CCallHelpers::NotEqual, m_result.payloadGPR(), CCallHelpers::TrustedImm64(negativeZeroBits));
 
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::NegZeroDouble), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(BinaryArithProfile::NegZeroDouble), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
         CCallHelpers::Jump done = jit.jump();
 
         notNegativeZero.link(&jit);
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::NonNegZeroDouble), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(BinaryArithProfile::NonNegZeroDouble), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
 
         jit.move(m_result.payloadGPR(), m_scratchGPR);
         jit.urshiftPtr(CCallHelpers::Imm32(52), m_scratchGPR);
         jit.and32(CCallHelpers::Imm32(0x7ff), m_scratchGPR);
         CCallHelpers::Jump noInt52Overflow = jit.branch32(CCallHelpers::LessThanOrEqual, m_scratchGPR, CCallHelpers::TrustedImm32(0x431));
 
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::Int52Overflow), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(BinaryArithProfile::Int52Overflow), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
         noInt52Overflow.link(&jit);
 
         done.link(&jit);
@@ -227,18 +227,18 @@
         notNegativeZero.append(jit.branch32(CCallHelpers::NotEqual, m_result.payloadGPR(), CCallHelpers::TrustedImm32(0)));
         notNegativeZero.append(jit.branch32(CCallHelpers::NotEqual, m_result.tagGPR(), CCallHelpers::TrustedImm32(negativeZeroBits >> 32)));
 
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::NegZeroDouble), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(BinaryArithProfile::NegZeroDouble), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
         CCallHelpers::Jump done = jit.jump();
 
         notNegativeZero.link(&jit);
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::NonNegZeroDouble), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(BinaryArithProfile::NonNegZeroDouble), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
 
         jit.move(m_result.tagGPR(), m_scratchGPR);
         jit.urshiftPtr(CCallHelpers::Imm32(52 - 32), m_scratchGPR);
         jit.and32(CCallHelpers::Imm32(0x7ff), m_scratchGPR);
         CCallHelpers::Jump noInt52Overflow = jit.branch32(CCallHelpers::LessThanOrEqual, m_scratchGPR, CCallHelpers::TrustedImm32(0x431));
         
-        jit.or32(CCallHelpers::TrustedImm32(ArithProfile::Int52Overflow), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
+        jit.or32(CCallHelpers::TrustedImm32(BinaryArithProfile::Int52Overflow), CCallHelpers::AbsoluteAddress(arithProfile->addressOfBits()));
 
         endJumpList.append(noInt52Overflow);
         if (m_scratchGPR == m_result.tagGPR() || m_scratchGPR == m_result.payloadGPR())
diff --git a/Source/JavaScriptCore/jit/JITMulGenerator.h b/Source/JavaScriptCore/jit/JITMulGenerator.h
index 36d26ea..6087796 100644
--- a/Source/JavaScriptCore/jit/JITMulGenerator.h
+++ b/Source/JavaScriptCore/jit/JITMulGenerator.h
@@ -56,8 +56,8 @@
         ASSERT(!m_leftOperand.isPositiveConstInt32() || !m_rightOperand.isPositiveConstInt32());
     }
 
-    JITMathICInlineResult generateInline(CCallHelpers&, MathICGenerationState&, const ArithProfile*);
-    bool generateFastPath(CCallHelpers&, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowJumpList, const ArithProfile*, bool shouldEmitProfiling);
+    JITMathICInlineResult generateInline(CCallHelpers&, MathICGenerationState&, const BinaryArithProfile*);
+    bool generateFastPath(CCallHelpers&, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowJumpList, const BinaryArithProfile*, bool shouldEmitProfiling);
 
     static bool isLeftOperandValidConstant(SnippetOperand leftOperand) { return leftOperand.isPositiveConstInt32(); }
     static bool isRightOperandValidConstant(SnippetOperand rightOperand) { return rightOperand.isPositiveConstInt32(); }
diff --git a/Source/JavaScriptCore/jit/JITNegGenerator.cpp b/Source/JavaScriptCore/jit/JITNegGenerator.cpp
index 92c29dd..ceebe39 100644
--- a/Source/JavaScriptCore/jit/JITNegGenerator.cpp
+++ b/Source/JavaScriptCore/jit/JITNegGenerator.cpp
@@ -32,7 +32,7 @@
 
 namespace JSC {
 
-JITMathICInlineResult JITNegGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const ArithProfile* arithProfile)
+JITMathICInlineResult JITNegGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const UnaryArithProfile* arithProfile)
 {
     ASSERT(m_scratchGPR != InvalidGPRReg);
     ASSERT(m_scratchGPR != m_src.payloadGPR());
@@ -45,7 +45,7 @@
     // We default to speculating int32.
     ObservedType observedTypes = ObservedType().withInt32();
     if (arithProfile)
-        observedTypes = arithProfile->lhsObservedType();
+        observedTypes = arithProfile->argObservedType();
     ASSERT_WITH_MESSAGE(!observedTypes.isEmpty(), "We should not attempt to generate anything if we do not have a profile.");
 
     if (observedTypes.isOnlyNonNumber())
@@ -82,7 +82,7 @@
     return JITMathICInlineResult::GenerateFullSnippet;
 }
 
-bool JITNegGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const ArithProfile* arithProfile, bool shouldEmitProfiling)
+bool JITNegGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const UnaryArithProfile* arithProfile, bool shouldEmitProfiling)
 {
     ASSERT(m_scratchGPR != m_src.payloadGPR());
     ASSERT(m_scratchGPR != m_result.payloadGPR());
@@ -117,7 +117,7 @@
 #endif
     // The flags of ArithNegate are basic in DFG.
     // We only need to know if we ever produced a number.
-    if (shouldEmitProfiling && arithProfile && !arithProfile->lhsObservedType().sawNumber() && !arithProfile->didObserveDouble())
+    if (shouldEmitProfiling && arithProfile && !arithProfile->argObservedType().sawNumber() && !arithProfile->didObserveDouble())
         arithProfile->emitSetDouble(jit);
     return true;
 }
diff --git a/Source/JavaScriptCore/jit/JITNegGenerator.h b/Source/JavaScriptCore/jit/JITNegGenerator.h
index 8a0c2d5..787b707 100644
--- a/Source/JavaScriptCore/jit/JITNegGenerator.h
+++ b/Source/JavaScriptCore/jit/JITNegGenerator.h
@@ -43,8 +43,8 @@
         , m_scratchGPR(scratchGPR)
     { }
 
-    JITMathICInlineResult generateInline(CCallHelpers&, MathICGenerationState&, const ArithProfile*);
-    bool generateFastPath(CCallHelpers&, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const ArithProfile*, bool shouldEmitProfiling);
+    JITMathICInlineResult generateInline(CCallHelpers&, MathICGenerationState&, const UnaryArithProfile*);
+    bool generateFastPath(CCallHelpers&, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const UnaryArithProfile*, bool shouldEmitProfiling);
 
 private:
     JSValueRegs m_result;
diff --git a/Source/JavaScriptCore/jit/JITOperations.cpp b/Source/JavaScriptCore/jit/JITOperations.cpp
index 639463c..1879459 100644
--- a/Source/JavaScriptCore/jit/JITOperations.cpp
+++ b/Source/JavaScriptCore/jit/JITOperations.cpp
@@ -2554,7 +2554,7 @@
     return JSValue::encode(jsAdd(exec, op1, op2));
 }
 
-ALWAYS_INLINE static EncodedJSValue profiledAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile)
+ALWAYS_INLINE static EncodedJSValue profiledAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile& arithProfile)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
@@ -2574,7 +2574,7 @@
     return unprofiledAdd(exec, encodedOp1, encodedOp2);
 }
 
-EncodedJSValue JIT_OPERATION operationValueAddProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile)
+EncodedJSValue JIT_OPERATION operationValueAddProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile* arithProfile)
 {
     ASSERT(arithProfile);
     return profiledAdd(exec, encodedOp1, encodedOp2, *arithProfile);
@@ -2588,7 +2588,7 @@
     JSValue op1 = JSValue::decode(encodedOp1);
     JSValue op2 = JSValue::decode(encodedOp2);
 
-    ArithProfile* arithProfile = addIC->arithProfile();
+    BinaryArithProfile* arithProfile = addIC->arithProfile();
     ASSERT(arithProfile);
     arithProfile->observeLHSAndRHS(op1, op2);
     auto nonOptimizeVariant = operationValueAddProfiledNoOptimize;
@@ -2609,7 +2609,7 @@
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    ArithProfile* arithProfile = addIC->arithProfile();
+    BinaryArithProfile* arithProfile = addIC->arithProfile();
     ASSERT(arithProfile);
     return profiledAdd(exec, encodedOp1, encodedOp2, *arithProfile);
 }
@@ -2623,7 +2623,7 @@
     JSValue op2 = JSValue::decode(encodedOp2);
 
     auto nonOptimizeVariant = operationValueAddNoOptimize;
-    if (ArithProfile* arithProfile = addIC->arithProfile())
+    if (BinaryArithProfile* arithProfile = addIC->arithProfile())
         arithProfile->observeLHSAndRHS(op1, op2);
     addIC->generateOutOfLine(exec->codeBlock(), nonOptimizeVariant);
 
@@ -2655,7 +2655,7 @@
     return JSValue::encode(jsMul(exec, op1, op2));
 }
 
-ALWAYS_INLINE static EncodedJSValue profiledMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
+ALWAYS_INLINE static EncodedJSValue profiledMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -2693,7 +2693,7 @@
     NativeCallFrameTracer tracer(vm, exec);
 
     auto nonOptimizeVariant = operationValueMulNoOptimize;
-    if (ArithProfile* arithProfile = mulIC->arithProfile())
+    if (BinaryArithProfile* arithProfile = mulIC->arithProfile())
         arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
     mulIC->generateOutOfLine(exec->codeBlock(), nonOptimizeVariant);
 
@@ -2704,7 +2704,7 @@
     return unprofiledMul(exec, encodedOp1, encodedOp2);
 }
 
-EncodedJSValue JIT_OPERATION operationValueMulProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile)
+EncodedJSValue JIT_OPERATION operationValueMulProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile* arithProfile)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
@@ -2718,7 +2718,7 @@
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    ArithProfile* arithProfile = mulIC->arithProfile();
+    BinaryArithProfile* arithProfile = mulIC->arithProfile();
     ASSERT(arithProfile);
     arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
     auto nonOptimizeVariant = operationValueMulProfiledNoOptimize;
@@ -2736,7 +2736,7 @@
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    ArithProfile* arithProfile = mulIC->arithProfile();
+    BinaryArithProfile* arithProfile = mulIC->arithProfile();
     ASSERT(arithProfile);
     return profiledMul(exec, encodedOp1, encodedOp2, *arithProfile);
 }
@@ -2760,14 +2760,14 @@
     return JSValue::encode(jsNumber(-number));
 }
 
-ALWAYS_INLINE static EncodedJSValue profiledNegate(ExecState* exec, EncodedJSValue encodedOperand, ArithProfile& arithProfile)
+ALWAYS_INLINE static EncodedJSValue profiledNegate(ExecState* exec, EncodedJSValue encodedOperand, UnaryArithProfile& arithProfile)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
     NativeCallFrameTracer tracer(vm, exec);
 
     JSValue operand = JSValue::decode(encodedOperand);
-    arithProfile.observeLHS(operand);
+    arithProfile.observeArg(operand);
     
     JSValue primValue = operand.toPrimitive(exec);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
@@ -2791,7 +2791,7 @@
     return unprofiledNegate(exec, operand);
 }
 
-EncodedJSValue JIT_OPERATION operationArithNegateProfiled(ExecState* exec, EncodedJSValue operand, ArithProfile* arithProfile)
+EncodedJSValue JIT_OPERATION operationArithNegateProfiled(ExecState* exec, EncodedJSValue operand, UnaryArithProfile* arithProfile)
 {
     ASSERT(arithProfile);
     return profiledNegate(exec, operand, *arithProfile);
@@ -2805,9 +2805,9 @@
     
     JSValue operand = JSValue::decode(encodedOperand);
 
-    ArithProfile* arithProfile = negIC->arithProfile();
+    UnaryArithProfile* arithProfile = negIC->arithProfile();
     ASSERT(arithProfile);
-    arithProfile->observeLHS(operand);
+    arithProfile->observeArg(operand);
     negIC->generateOutOfLine(exec->codeBlock(), operationArithNegateProfiled);
 
 #if ENABLE(MATH_IC_STATS)
@@ -2838,8 +2838,8 @@
 
     JSValue operand = JSValue::decode(encodedOperand);
 
-    if (ArithProfile* arithProfile = negIC->arithProfile())
-        arithProfile->observeLHS(operand);
+    if (UnaryArithProfile* arithProfile = negIC->arithProfile())
+        arithProfile->observeArg(operand);
     negIC->generateOutOfLine(exec->codeBlock(), operationArithNegate);
 
 #if ENABLE(MATH_IC_STATS)
@@ -2865,7 +2865,7 @@
     return JSValue::encode(jsSub(exec, op1, op2));
 }
 
-ALWAYS_INLINE static EncodedJSValue profiledSub(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
+ALWAYS_INLINE static EncodedJSValue profiledSub(VM& vm, ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile& arithProfile, bool shouldObserveLHSAndRHSTypes = true)
 {
     auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -2888,7 +2888,7 @@
     return unprofiledSub(exec, encodedOp1, encodedOp2);
 }
 
-EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile* arithProfile)
+EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile* arithProfile)
 {
     ASSERT(arithProfile);
 
@@ -2904,7 +2904,7 @@
     NativeCallFrameTracer tracer(vm, exec);
 
     auto nonOptimizeVariant = operationValueSubNoOptimize;
-    if (ArithProfile* arithProfile = subIC->arithProfile())
+    if (BinaryArithProfile* arithProfile = subIC->arithProfile())
         arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
     subIC->generateOutOfLine(exec->codeBlock(), nonOptimizeVariant);
 
@@ -2928,7 +2928,7 @@
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    ArithProfile* arithProfile = subIC->arithProfile();
+    BinaryArithProfile* arithProfile = subIC->arithProfile();
     ASSERT(arithProfile);
     arithProfile->observeLHSAndRHS(JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
     auto nonOptimizeVariant = operationValueSubProfiledNoOptimize;
@@ -2946,7 +2946,7 @@
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
 
-    ArithProfile* arithProfile = subIC->arithProfile();
+    BinaryArithProfile* arithProfile = subIC->arithProfile();
     ASSERT(arithProfile);
     return profiledSub(vm, exec, encodedOp1, encodedOp2, *arithProfile);
 }
diff --git a/Source/JavaScriptCore/jit/JITOperations.h b/Source/JavaScriptCore/jit/JITOperations.h
index 9db6734..3b6aaf0 100644
--- a/Source/JavaScriptCore/jit/JITOperations.h
+++ b/Source/JavaScriptCore/jit/JITOperations.h
@@ -38,6 +38,8 @@
     
 class ArrayAllocationProfile;
 class ArrayProfile;
+class UnaryArithProfile;
+class BinaryArithProfile;
 class Butterfly;
 class CallFrame;
 class CallLinkInfo;
@@ -64,7 +66,6 @@
 struct ByValInfo;
 struct InlineCallFrame;
 struct Instruction;
-struct ArithProfile;
 
 using ExecState = CallFrame;
 
@@ -79,7 +80,7 @@
     A: JSArray*
     Aap: ArrayAllocationProfile*
     Ap: ArrayProfile*
-    Arp: ArithProfile*
+    Arp: BinaryArithProfile*
     B: Butterfly*
     By: ByValInfo*
     C: JSCell*
@@ -145,13 +146,13 @@
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJC)(ExecState*, EncodedJSValue, JSCell*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJA)(ExecState*, EncodedJSValue, JSArray*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EAPZ)(ExecState*, JSArray*, void*, int32_t);
-typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJArp)(ExecState*, EncodedJSValue, ArithProfile*);
+typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJArp)(ExecState*, EncodedJSValue, BinaryArithProfile*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJI)(ExecState*, EncodedJSValue, UniquedStringImpl*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, EncodedJSValue);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJAp)(ExecState*, EncodedJSValue, EncodedJSValue, ArrayProfile*);
-typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJArp)(ExecState*, EncodedJSValue, EncodedJSValue, ArithProfile*);
+typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJArp)(ExecState*, EncodedJSValue, EncodedJSValue, BinaryArithProfile*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJBy)(ExecState*, EncodedJSValue, EncodedJSValue, ByValInfo*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJJMic)(ExecState*, EncodedJSValue, EncodedJSValue, void*);
 typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EJMic)(ExecState*, EncodedJSValue, void*);
@@ -482,7 +483,7 @@
 int32_t JIT_OPERATION operationInstanceOfCustom(ExecState*, EncodedJSValue encodedValue, JSObject* constructor, EncodedJSValue encodedHasInstance) WTF_INTERNAL;
 
 EncodedJSValue JIT_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationValueAddProfiled(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationValueAddProfiled(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueAddProfiledOptimize(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITAddIC*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueAddProfiledNoOptimize(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITAddIC*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueAddOptimize(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITAddIC*) WTF_INTERNAL;
@@ -492,13 +493,13 @@
 EncodedJSValue JIT_OPERATION operationValueMulNoOptimize(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueMulProfiledOptimize(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueMulProfiledNoOptimize(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITMulIC*) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationValueMulProfiled(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationValueMulProfiled(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArithNegate(ExecState*, EncodedJSValue operand);
-EncodedJSValue JIT_OPERATION operationArithNegateProfiled(ExecState*, EncodedJSValue operand, ArithProfile*);
+EncodedJSValue JIT_OPERATION operationArithNegateProfiled(ExecState*, EncodedJSValue operand, UnaryArithProfile*);
 EncodedJSValue JIT_OPERATION operationArithNegateProfiledOptimize(ExecState*, EncodedJSValue encodedOperand, JITNegIC*);
 EncodedJSValue JIT_OPERATION operationArithNegateOptimize(ExecState*, EncodedJSValue encodedOperand, JITNegIC*);
 EncodedJSValue JIT_OPERATION operationValueSub(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, ArithProfile*) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationValueSubProfiled(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BinaryArithProfile*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueSubOptimize(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueSubNoOptimize(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationValueSubProfiledOptimize(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, JITSubIC*) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/jit/JITSubGenerator.cpp b/Source/JavaScriptCore/jit/JITSubGenerator.cpp
index 795c275..7b1a8b8 100644
--- a/Source/JavaScriptCore/jit/JITSubGenerator.cpp
+++ b/Source/JavaScriptCore/jit/JITSubGenerator.cpp
@@ -33,7 +33,7 @@
 
 namespace JSC {
 
-JITMathICInlineResult JITSubGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const ArithProfile* arithProfile)
+JITMathICInlineResult JITSubGenerator::generateInline(CCallHelpers& jit, MathICGenerationState& state, const BinaryArithProfile* arithProfile)
 {
     // We default to speculating int32.
     ObservedType lhs = ObservedType().withInt32();
@@ -78,7 +78,7 @@
     return JITMathICInlineResult::GenerateFullSnippet;
 }
 
-bool JITSubGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const ArithProfile* arithProfile, bool shouldEmitProfiling)
+bool JITSubGenerator::generateFastPath(CCallHelpers& jit, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const BinaryArithProfile* arithProfile, bool shouldEmitProfiling)
 {
     ASSERT(m_scratchGPR != InvalidGPRReg);
     ASSERT(m_scratchGPR != m_left.payloadGPR());
diff --git a/Source/JavaScriptCore/jit/JITSubGenerator.h b/Source/JavaScriptCore/jit/JITSubGenerator.h
index 561f633..3491a83 100644
--- a/Source/JavaScriptCore/jit/JITSubGenerator.h
+++ b/Source/JavaScriptCore/jit/JITSubGenerator.h
@@ -53,8 +53,8 @@
         , m_scratchFPR(scratchFPR)
     { }
 
-    JITMathICInlineResult generateInline(CCallHelpers&, MathICGenerationState&, const ArithProfile*);
-    bool generateFastPath(CCallHelpers&, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const ArithProfile*, bool shouldEmitProfiling);
+    JITMathICInlineResult generateInline(CCallHelpers&, MathICGenerationState&, const BinaryArithProfile*);
+    bool generateFastPath(CCallHelpers&, CCallHelpers::JumpList& endJumpList, CCallHelpers::JumpList& slowPathJumpList, const BinaryArithProfile*, bool shouldEmitProfiling);
 
     static bool isLeftOperandValidConstant(SnippetOperand) { return false; }
     static bool isRightOperandValidConstant(SnippetOperand) { return false; }
diff --git a/Source/JavaScriptCore/llint/LLIntData.cpp b/Source/JavaScriptCore/llint/LLIntData.cpp
index bda308c..c0341c9 100644
--- a/Source/JavaScriptCore/llint/LLIntData.cpp
+++ b/Source/JavaScriptCore/llint/LLIntData.cpp
@@ -135,36 +135,49 @@
 #endif
 
     {
-        ArithProfile arithProfile;
+        UnaryArithProfile arithProfile;
+        arithProfile.argSawInt32();
+        ASSERT(arithProfile.bits() == UnaryArithProfile::observedIntBits());
+        ASSERT(arithProfile.argObservedType().isOnlyInt32());
+    }
+    {
+        UnaryArithProfile arithProfile;
+        arithProfile.argSawNumber();
+        ASSERT(arithProfile.bits() == UnaryArithProfile::observedNumberBits());
+        ASSERT(arithProfile.argObservedType().isOnlyNumber());
+    }
+
+    {
+        BinaryArithProfile arithProfile;
         arithProfile.lhsSawInt32();
         arithProfile.rhsSawInt32();
-        ASSERT(arithProfile.bits() == ArithProfile::observedBinaryIntInt().bits());
-        STATIC_ASSERT(ArithProfile::observedBinaryIntInt().lhsObservedType().isOnlyInt32());
-        STATIC_ASSERT(ArithProfile::observedBinaryIntInt().rhsObservedType().isOnlyInt32());
+        ASSERT(arithProfile.bits() == BinaryArithProfile::observedIntIntBits());
+        ASSERT(arithProfile.lhsObservedType().isOnlyInt32());
+        ASSERT(arithProfile.rhsObservedType().isOnlyInt32());
     }
     {
-        ArithProfile arithProfile;
+        BinaryArithProfile arithProfile;
         arithProfile.lhsSawNumber();
         arithProfile.rhsSawInt32();
-        ASSERT(arithProfile.bits() == ArithProfile::observedBinaryNumberInt().bits());
-        STATIC_ASSERT(ArithProfile::observedBinaryNumberInt().lhsObservedType().isOnlyNumber());
-        STATIC_ASSERT(ArithProfile::observedBinaryNumberInt().rhsObservedType().isOnlyInt32());
+        ASSERT(arithProfile.bits() == BinaryArithProfile::observedNumberIntBits());
+        ASSERT(arithProfile.lhsObservedType().isOnlyNumber());
+        ASSERT(arithProfile.rhsObservedType().isOnlyInt32());
     }
     {
-        ArithProfile arithProfile;
+        BinaryArithProfile arithProfile;
         arithProfile.lhsSawNumber();
         arithProfile.rhsSawNumber();
-        ASSERT(arithProfile.bits() == ArithProfile::observedBinaryNumberNumber().bits());
-        STATIC_ASSERT(ArithProfile::observedBinaryNumberNumber().lhsObservedType().isOnlyNumber());
-        STATIC_ASSERT(ArithProfile::observedBinaryNumberNumber().rhsObservedType().isOnlyNumber());
+        ASSERT(arithProfile.bits() == BinaryArithProfile::observedNumberNumberBits());
+        ASSERT(arithProfile.lhsObservedType().isOnlyNumber());
+        ASSERT(arithProfile.rhsObservedType().isOnlyNumber());
     }
     {
-        ArithProfile arithProfile;
+        BinaryArithProfile arithProfile;
         arithProfile.lhsSawInt32();
         arithProfile.rhsSawNumber();
-        ASSERT(arithProfile.bits() == ArithProfile::observedBinaryIntNumber().bits());
-        STATIC_ASSERT(ArithProfile::observedBinaryIntNumber().lhsObservedType().isOnlyInt32());
-        STATIC_ASSERT(ArithProfile::observedBinaryIntNumber().rhsObservedType().isOnlyNumber());
+        ASSERT(arithProfile.bits() == BinaryArithProfile::observedIntNumberBits());
+        ASSERT(arithProfile.lhsObservedType().isOnlyInt32());
+        ASSERT(arithProfile.rhsObservedType().isOnlyNumber());
     }
 }
 IGNORE_WARNINGS_END
diff --git a/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp b/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
index a25f984..f5d9177 100644
--- a/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
+++ b/Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
@@ -86,7 +86,7 @@
 
 const int64_t* LLIntOffsetsExtractor::dummy()
 {
-// This is a file generated by offlineasm/generate_offsets_extractor.rb, and contains code
+// This is a file generated by offlineasm/generate_offset_extractor.rb, and contains code
 // to create a table of offsets, sizes, and a header identifying what combination of
 // Platform.h macros we have set. We include it inside of a method on LLIntOffsetsExtractor
 // because the fields whose offsets we're extracting are mostly private. So we make their
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index c3d17d8..6fd1698 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -240,13 +240,15 @@
 # ShadowChicken data
 const ShadowChickenTailMarker = constexpr ShadowChicken::Packet::tailMarkerValue
 
-# ArithProfile data
-const ArithProfileInt = constexpr (ArithProfile::observedUnaryInt().bits())
-const ArithProfileNumber = constexpr (ArithProfile::observedUnaryNumber().bits())
-const ArithProfileIntInt = constexpr (ArithProfile::observedBinaryIntInt().bits())
-const ArithProfileNumberInt = constexpr (ArithProfile::observedBinaryNumberInt().bits())
-const ArithProfileIntNumber = constexpr (ArithProfile::observedBinaryIntNumber().bits())
-const ArithProfileNumberNumber = constexpr (ArithProfile::observedBinaryNumberNumber().bits())
+# UnaryArithProfile data
+const ArithProfileInt = constexpr (UnaryArithProfile::observedIntBits())
+const ArithProfileNumber = constexpr (UnaryArithProfile::observedNumberBits())
+
+# BinaryArithProfile data
+const ArithProfileIntInt = constexpr (BinaryArithProfile::observedIntIntBits())
+const ArithProfileNumberInt = constexpr (BinaryArithProfile::observedNumberIntBits())
+const ArithProfileIntNumber = constexpr (BinaryArithProfile::observedIntNumberBits())
+const ArithProfileNumberNumber = constexpr (BinaryArithProfile::observedNumberNumberBits())
 
 # Pointer Tags
 const BytecodePtrTag = constexpr BytecodePtrTag
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index 30435c4..590bc7e 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -1004,7 +1004,7 @@
 llintOpWithMetadata(op_negate, OpNegate, macro (size, get, dispatch, metadata, return)
 
     macro arithProfile(type)
-        ori type, OpNegate::Metadata::m_arithProfile + ArithProfile::m_bits[t5]
+        ori type, OpNegate::Metadata::m_arithProfile + BinaryArithProfile::m_bits[t5]
     end
 
     metadata(t5, t0)
@@ -1030,7 +1030,7 @@
 macro binaryOpCustomStore(opcodeName, opcodeStruct, integerOperationAndStore, doubleOperation)
     llintOpWithMetadata(op_%opcodeName%, opcodeStruct, macro (size, get, dispatch, metadata, return)
         macro arithProfile(type)
-            ori type, %opcodeStruct%::Metadata::m_arithProfile + ArithProfile::m_bits[t5]
+            ori type, %opcodeStruct%::Metadata::m_arithProfile + BinaryArithProfile::m_bits[t5]
         end
 
         metadata(t5, t2)
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
index b2fb551..059b5a3 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
@@ -976,19 +976,19 @@
     get(m_operand, t0)
     loadConstantOrVariable(size, t0, t3)
     metadata(t1, t2)
-    loadi OpNegate::Metadata::m_arithProfile + ArithProfile::m_bits[t1], t2
+    loadi OpNegate::Metadata::m_arithProfile + BinaryArithProfile::m_bits[t1], t2
     bqb t3, numberTag, .opNegateNotInt
     btiz t3, 0x7fffffff, .opNegateSlow
     negi t3
     orq numberTag, t3
     ori ArithProfileInt, t2
-    storei t2, OpNegate::Metadata::m_arithProfile + ArithProfile::m_bits[t1]
+    storei t2, OpNegate::Metadata::m_arithProfile + BinaryArithProfile::m_bits[t1]
     return(t3)
 .opNegateNotInt:
     btqz t3, numberTag, .opNegateSlow
     xorq 0x8000000000000000, t3
     ori ArithProfileNumber, t2
-    storei t2, OpNegate::Metadata::m_arithProfile + ArithProfile::m_bits[t1]
+    storei t2, OpNegate::Metadata::m_arithProfile + BinaryArithProfile::m_bits[t1]
     return(t3)
 
 .opNegateSlow:
@@ -1002,7 +1002,7 @@
         metadata(t5, t0)
 
         macro profile(type)
-            ori type, %opcodeStruct%::Metadata::m_arithProfile + ArithProfile::m_bits[t5]
+            ori type, %opcodeStruct%::Metadata::m_arithProfile + BinaryArithProfile::m_bits[t5]
         end
 
         get(m_rhs, t0)
diff --git a/Source/JavaScriptCore/parser/ResultType.h b/Source/JavaScriptCore/parser/ResultType.h
index 9b3d0d7..5622f28 100644
--- a/Source/JavaScriptCore/parser/ResultType.h
+++ b/Source/JavaScriptCore/parser/ResultType.h
@@ -48,6 +48,10 @@
         static constexpr int numBitsNeeded = 7;
         static_assert((TypeBits & ((1 << numBitsNeeded) - 1)) == TypeBits, "This is necessary for correctness.");
 
+        constexpr explicit ResultType()
+            : ResultType(unknownType())
+        {
+        }
         constexpr explicit ResultType(Type type)
             : m_bits(type)
         {
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
index 924f7e5..340b900 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
@@ -487,8 +487,8 @@
 #if ENABLE(JIT)
 static void updateArithProfileForUnaryArithOp(OpNegate::Metadata& metadata, JSValue result, JSValue operand)
 {
-    ArithProfile& profile = metadata.m_arithProfile;
-    profile.observeLHS(operand);
+    UnaryArithProfile& profile = metadata.m_arithProfile;
+    profile.observeArg(operand);
     ASSERT(result.isNumber() || result.isBigInt());
     if (result.isNumber()) {
         if (!result.isInt32()) {
@@ -546,7 +546,7 @@
 static void updateArithProfileForBinaryArithOp(ExecState* exec, const Instruction* pc, JSValue result, JSValue left, JSValue right)
 {
     CodeBlock* codeBlock = exec->codeBlock();
-    ArithProfile& profile = *codeBlock->arithProfileForPC(pc);
+    BinaryArithProfile& profile = *codeBlock->binaryArithProfileForPC(pc);
 
     if (result.isNumber()) {
         if (!result.isInt32()) {
@@ -607,7 +607,7 @@
     JSValue v1 = GET_C(bytecode.m_lhs).jsValue();
     JSValue v2 = GET_C(bytecode.m_rhs).jsValue();
 
-    ArithProfile& arithProfile = *exec->codeBlock()->arithProfileForPC(pc);
+    BinaryArithProfile& arithProfile = *exec->codeBlock()->binaryArithProfileForPC(pc);
     arithProfile.observeLHSAndRHS(v1, v2);
 
     JSValue result = jsAdd(exec, v1, v2);