<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[260331] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/260331">260331</a></dd>
<dt>Author</dt> <dd>rmorisset@apple.com</dd>
<dt>Date</dt> <dd>2020-04-18 19:20:59 -0700 (Sat, 18 Apr 2020)</dd>
</dl>

<h3>Log Message</h3>
<pre>Support an inlined representation in JSValue of small BigInts ("BigInt32")
https://bugs.webkit.org/show_bug.cgi?id=206182

Reviewed by Yusuke Suzuki.

JSTests:

I improved several of the tests to give more informative error messages in the process of fixing them.

More interestingly I had to modify "missing-exception-check-in-string-compare" because it relied on "s1 == s1" resolving ropes, and we now just return true.

* stress/big-int-division.js:
(testDiv):
* stress/big-int-left-shift-wrapped-value.js:
(assert.sameValue):
* stress/big-int-logical-not.js:
(assert):
* stress/big-int-mod-jit.js:
* stress/big-int-right-shift-general.js:
(testRightShift):
* stress/big-int-type-of-proven-type.js:
(assert):
* stress/compare-strict-eq-on-various-types.js:
(testAllTypesCall):
* stress/ftl-string-strict-equality.js:
* stress/missing-exception-check-in-string-compare.js:

Source/JavaScriptCore:

This patch attempts to optimize the performance of BigInts, when they are small (32 bit or less).
It works by inlining them into JSValue on 64-bit platforms, avoiding the allocation of a JSBigInt.
The bit pattern we use is 0000:XXXX:XXXX:0012
This representation works because of the following things:
- It cannot be confused with a Double or Integer thanks to the top bits
- It cannot be confused with a pointer to a Cell, thanks to bit 1 which is set to true
- It cannot be confused with a pointer to wasm thanks to bit 0 which is set to false
- It cannot be confused with true/false because bit 2 is set to false
- It cannot be confused for null/undefined because bit 4 is set to true

This entire change is gated by USE(BIGINT32), to make it easier to disable if it turns out to have bugs.
It should also make it much easier to verify if a given bug comes from it or from something else.

Note that in this patch we create BigInt32s when parsing small BigInt constants, and most operations (e.g. Add or BitOr) produce a BigInt32 if both of their operands are BigInt32,
but we don't produce a BigInt32 from for example the substraction/division of two large heap-allocated JSBigInts, even if the result fits in 32-bits.
As a result, small BigInts can now either be heap-allocated or inlined in the JSValue.

This patch includes a significant refactor of various slow paths, which are now grouped together in Operations.h
Because this increased the size of Operations.h significantly, I split the parts of Operations.h which are only used by the GC into Scribble.h, to avoid bloating compile times.

In the DFG and FTL we now have 3 UseKinds for BigInts: HeapBigIntUse, BigInt32Use and AnyBigIntUse.
The latter is useful when we know that we are receiving BigInts, but speculation indicates a mix of heap-allocated and small (inlined) big-ints.

Unfortunately, a naive implementation of this patch significantly regresses the performance of StrictEq (and its variants), as it is no longer true that a cell and a non-cell cannot be equal.
Before this patch, the code was jumping to a slow path if either:
- at least one operand is a double
- or both operands are cells
Now, it also needs to jump to the slow path if at least one is a cell.
To recover this performance cost, I significantly rewrote this code, from
  if (left is Cell && right is Cell) {
    if (left == right)
      return true;
    goto slowPath;
  }
  if (! left is Int32) {
    if (left is Number)
      goto slowPath
  }
  if (! right is Int32) {
    if (right is Number)
      goto slowPath
  }
  return left == right
To the following:
  if (left is Double || right is Double)
    goto slowPath
  if (left == right)
    return true;
  if (left is Cell || right is Cell)
    goto slowPath
  return false;
I believe this to be faster than just replacing (left is Cell && right is Cell) by an ||, because I found a bit-trick to check (left is Double || right is Double) which should help reduce the pressure on the branch predictor.
Early JetStream2 tests appear to confirm that this patch is roughly neutral while it was a 0.5% regression before I used this trick, but the numbers are still too noisy, I plan to do more measurements before landing this patch.

I don't yet have performance numbers for this patch on a BigInt benchmark, I will get such numbers before trying to land it, but I'd like some review in the meantime.

* JavaScriptCore.xcodeproj/project.pbxproj:
* assembler/X86Assembler.h:
(JSC::X86Assembler::X86InstructionFormatter::SingleInstructionBufferWriter::memoryModRM):
* bytecode/ArithProfile.cpp:
(JSC::ArithProfile<BitfieldType>::emitObserveResult):
(JSC::ArithProfile<BitfieldType>::shouldEmitSetBigInt32 const):
(JSC::ArithProfile<BitfieldType>::shouldEmitSetHeapBigInt const):
(JSC::ArithProfile<BitfieldType>::emitSetHeapBigInt const):
(JSC::ArithProfile<BitfieldType>::emitSetBigInt32 const):
(WTF::printInternal):
* bytecode/ArithProfile.h:
(JSC::ObservedResults::didObserveNonInt32):
(JSC::ObservedResults::didObserveBigInt):
(JSC::ObservedResults::didObserveHeapBigInt):
(JSC::ObservedResults::didObserveBigInt32):
(JSC::ArithProfile::didObserveHeapBigInt const):
(JSC::ArithProfile::didObserveBigInt32 const):
(JSC::ArithProfile::setObservedHeapBigInt):
(JSC::ArithProfile::setObservedBigInt32):
(JSC::ArithProfile::observeResult):
* bytecode/BytecodeList.rb:
* bytecode/BytecodeLivenessAnalysisInlines.h:
* bytecode/BytecodeUseDef.cpp:
(JSC::computeUsesForBytecodeIndexImpl):
(JSC::computeDefsForBytecodeIndexImpl):
* bytecode/CodeBlock.cpp:
* bytecode/DataFormat.h:
* bytecode/MethodOfGettingAValueProfile.cpp:
(JSC::MethodOfGettingAValueProfile::emitReportValue const):
* bytecode/MethodOfGettingAValueProfile.h:
* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationFromClassInfo):
(JSC::speculationFromStructure):
(JSC::speculationFromValue):
(JSC::speculationFromJSType):
(JSC::leastUpperBoundOfStrictlyEquivalentSpeculations):
* bytecode/SpeculatedType.h:
(JSC::isBigInt32Speculation):
(JSC::isHeapBigIntSpeculation):
(JSC::isBigIntSpeculation):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitEqualityOpImpl):
(JSC::BytecodeGenerator::addBigIntConstant):
* bytecompiler/BytecodeGenerator.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::isToThisAnIdentity):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupToThis):
(JSC::DFG::FixupPhase::fixupToNumeric):
(JSC::DFG::FixupPhase::observeUseKindOnNode):
(JSC::DFG::FixupPhase::fixupCompareStrictEqAndSameValue):
* dfg/DFGMayExit.cpp:
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldSpeculateBigInt32):
(JSC::DFG::Node::shouldSpeculateHeapBigInt):
* dfg/DFGNodeType.h:
* dfg/DFGOSRExit.cpp:
(JSC::DFG::OSRExit::compileExit):
* dfg/DFGOSRExit.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
(JSC::DFG::SpeculativeJIT::compileValueBitNot):
(JSC::DFG::SpeculativeJIT::emitUntypedOrAnyBigIntBitOp):
(JSC::DFG::SpeculativeJIT::compileValueBitwiseOp):
(JSC::DFG::SpeculativeJIT::emitUntypedOrBigIntRightShiftBitOp):
(JSC::DFG::SpeculativeJIT::compileValueLShiftOp):
(JSC::DFG::SpeculativeJIT::compileValueBitRShift):
(JSC::DFG::SpeculativeJIT::compileShiftOp):
(JSC::DFG::SpeculativeJIT::compileValueAdd):
(JSC::DFG::SpeculativeJIT::compileValueSub):
(JSC::DFG::SpeculativeJIT::compileIncOrDec):
(JSC::DFG::SpeculativeJIT::compileValueNegate):
(JSC::DFG::SpeculativeJIT::compileValueMul):
(JSC::DFG::SpeculativeJIT::compileValueDiv):
(JSC::DFG::SpeculativeJIT::compileValueMod):
(JSC::DFG::SpeculativeJIT::compileValuePow):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileStrictEq):
(JSC::DFG::SpeculativeJIT::speculateHeapBigInt):
(JSC::DFG::SpeculativeJIT::speculate):
(JSC::DFG::SpeculativeJIT::compileToNumeric):
(JSC::DFG::SpeculativeJIT::compileHeapBigIntEquality):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculateBigInt32Operand::SpeculateBigInt32Operand):
(JSC::DFG::SpeculateBigInt32Operand::~SpeculateBigInt32Operand):
(JSC::DFG::SpeculateBigInt32Operand::edge const):
(JSC::DFG::SpeculateBigInt32Operand::node const):
(JSC::DFG::SpeculateBigInt32Operand::gpr):
(JSC::DFG::SpeculateBigInt32Operand::use):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::fillJSValue):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeStrictEq):
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq):
(JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::speculateBigInt32):
(JSC::DFG::SpeculativeJIT::speculateAnyBigInt):
(JSC::DFG::SpeculativeJIT::fillSpeculateBigInt32):
(JSC::DFG::SpeculativeJIT::compileBigInt32Compare):
(JSC::DFG::SpeculativeJIT::compilePeepHoleBigInt32Branch):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStrengthReductionPhase.cpp:
(JSC::DFG::StrengthReductionPhase::handleNode):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isCell):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLCommonValues.cpp:
(JSC::FTL::CommonValues::initializeConstants):
* ftl/FTLCommonValues.h:
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileValueAdd):
(JSC::FTL::DFG::LowerDFGToB3::compileValueSub):
(JSC::FTL::DFG::LowerDFGToB3::compileValueMul):
(JSC::FTL::DFG::LowerDFGToB3::compileBinaryMathIC):
(JSC::FTL::DFG::LowerDFGToB3::compileValueDiv):
(JSC::FTL::DFG::LowerDFGToB3::compileValueMod):
(JSC::FTL::DFG::LowerDFGToB3::compileValuePow):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitNot):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitAnd):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitOr):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitXor):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitRShift):
(JSC::FTL::DFG::LowerDFGToB3::compileArithBitRShift):
(JSC::FTL::DFG::LowerDFGToB3::compileArithBitLShift):
(JSC::FTL::DFG::LowerDFGToB3::compileValueBitLShift):
(JSC::FTL::DFG::LowerDFGToB3::compileBitURShift):
(JSC::FTL::DFG::LowerDFGToB3::compileToNumeric):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareEq):
(JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
(JSC::FTL::DFG::LowerDFGToB3::compileIsBigInt):
(JSC::FTL::DFG::LowerDFGToB3::emitBinarySnippet):
(JSC::FTL::DFG::LowerDFGToB3::emitBinaryBitOpSnippet):
(JSC::FTL::DFG::LowerDFGToB3::boolify):
(JSC::FTL::DFG::LowerDFGToB3::buildTypeOf):
(JSC::FTL::DFG::LowerDFGToB3::lowHeapBigInt):
(JSC::FTL::DFG::LowerDFGToB3::lowBigInt32):
(JSC::FTL::DFG::LowerDFGToB3::isBigInt32):
(JSC::FTL::DFG::LowerDFGToB3::isNotBigInt32):
(JSC::FTL::DFG::LowerDFGToB3::unboxBigInt32):
(JSC::FTL::DFG::LowerDFGToB3::boxBigInt32):
(JSC::FTL::DFG::LowerDFGToB3::isNotAnyBigInt):
(JSC::FTL::DFG::LowerDFGToB3::speculate):
(JSC::FTL::DFG::LowerDFGToB3::isNotHeapBigIntUnknownWhetherCell):
(JSC::FTL::DFG::LowerDFGToB3::isNotHeapBigInt):
(JSC::FTL::DFG::LowerDFGToB3::isHeapBigInt):
(JSC::FTL::DFG::LowerDFGToB3::speculateHeapBigInt):
(JSC::FTL::DFG::LowerDFGToB3::speculateHeapBigIntUnknownWhetherCell):
(JSC::FTL::DFG::LowerDFGToB3::speculateBigInt32):
(JSC::FTL::DFG::LowerDFGToB3::speculateAnyBigInt):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):
* heap/HeapSnapshotBuilder.cpp:
(JSC::HeapSnapshotBuilder::json):
* heap/MarkedBlockInlines.h:
* heap/PreciseAllocation.cpp:
* inspector/agents/InspectorHeapAgent.cpp:
(Inspector::InspectorHeapAgent::getPreview):
* interpreter/Interpreter.cpp:
(JSC::sizeOfVarargs):
* jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::emitConvertValueToBoolean):
(JSC::AssemblyHelpers::branchIfValue):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::branchIfBigInt32):
(JSC::AssemblyHelpers::branchIfBigInt32KnownNotNumber):
(JSC::AssemblyHelpers::branchIfNotBigInt32KnownNotNumber):
(JSC::AssemblyHelpers::branchIfHeapBigInt):
(JSC::AssemblyHelpers::branchIfNotHeapBigInt):
(JSC::AssemblyHelpers::unboxBigInt32):
(JSC::AssemblyHelpers::boxBigInt32):
(JSC::AssemblyHelpers::emitTypeOf):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITArithmetic.cpp:
(JSC::JIT::emit_op_negate):
(JSC::JIT::emitSlow_op_negate):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_is_big_int):
(JSC::JIT::compileOpStrictEq):
(JSC::JIT::compileOpStrictEqJump):
(JSC::JIT::emit_op_to_numeric):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_is_big_int):
(JSC::JIT::emit_op_to_numeric):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* llint/LLIntOfflineAsmConfig.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter64.asm:
* parser/ParserArena.cpp:
(JSC::IdentifierArena::makeBigIntDecimalIdentifier):
* runtime/ArrayPrototype.cpp:
* runtime/BigIntConstructor.cpp:
(JSC::toBigInt):
(JSC::callBigIntConstructor):
* runtime/BigIntObject.cpp:
(JSC::BigIntObject::create):
(JSC::BigIntObject::finishCreation):
* runtime/BigIntObject.h:
* runtime/BigIntPrototype.cpp:
(JSC::toThisBigIntValue):
(JSC::bigIntProtoFuncToStringImpl):
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
(JSC::updateArithProfileForUnaryArithOp):
(JSC::updateArithProfileForBinaryArithOp):
* runtime/JSBigInt.cpp:
(JSC::JSBigInt::createStructure):
(JSC::JSBigInt::parseInt):
(JSC::JSBigInt::stringToBigInt):
(JSC::JSBigInt::inc):
(JSC::JSBigInt::dec):
(JSC::JSBigInt::bitwiseAnd):
(JSC::JSBigInt::toStringGeneric):
(JSC::JSBigInt::equalsToNumber):
(JSC::JSBigInt::equalsToInt32):
* runtime/JSBigInt.h:
(JSC::asHeapBigInt):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::toNumberSlowCase const):
(JSC::JSValue::toObjectSlowCase const):
(JSC::JSValue::toThisSlowCase const):
(JSC::JSValue::synthesizePrototype const):
(JSC::JSValue::dumpInContextAssumingStructure const):
(JSC::JSValue::dumpForBacktrace const):
(JSC::JSValue::toStringSlowCase const):
* runtime/JSCJSValue.h:
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::JSValue):
(JSC::JSValue::asHeapBigInt const):
(JSC::JSValue::isBigInt const):
(JSC::JSValue::isHeapBigInt const):
(JSC::JSValue::isBigInt32 const):
(JSC::JSValue::bigInt32AsInt32 const):
(JSC::JSValue::isPrimitive const):
(JSC::JSValue::getPrimitiveNumber):
(JSC::JSValue::toNumeric const):
(JSC::JSValue::toBigIntOrInt32 const):
(JSC::JSValue::equalSlowCaseInline):
(JSC::JSValue::strictEqualForCells):
(JSC::JSValue::strictEqual):
(JSC::JSValue::pureStrictEqual):
(JSC::JSValue::pureToBoolean const):
* runtime/JSCell.cpp:
(JSC::JSCell::put):
(JSC::JSCell::putByIndex):
(JSC::JSCell::toPrimitive const):
(JSC::JSCell::getPrimitiveNumber const):
(JSC::JSCell::toNumber const):
(JSC::JSCell::toObjectSlow const):
* runtime/JSCell.h:
* runtime/JSCellInlines.h:
(JSC::JSCell::isHeapBigInt const):
(JSC::JSCell::toBoolean const):
(JSC::JSCell::pureToBoolean const):
* runtime/JSString.h:
(JSC::JSValue::toBoolean const):
* runtime/JSType.cpp:
(WTF::printInternal):
* runtime/JSType.h:
* runtime/JSTypeInfo.h:
* runtime/ObjectInitializationScope.cpp:
* runtime/Operations.cpp:
(JSC::jsAddSlowCase):
(JSC::jsIsObjectTypeOrNull):
* runtime/Operations.h:
(JSC::compareBigIntToOtherPrimitive):
(JSC::bigIntCompare):
(JSC::jsLess):
(JSC::jsLessEq):
(JSC::arithmeticBinaryOp):
(JSC::jsSub):
(JSC::jsMul):
(JSC::jsDiv):
(JSC::jsRemainder):
(JSC::jsPow):
(JSC::jsInc):
(JSC::jsDec):
(JSC::jsBitwiseNot):
(JSC::shift):
(JSC::jsLShift):
(JSC::jsRShift):
(JSC::bitwiseBinaryOp):
(JSC::jsBitwiseAnd):
(JSC::jsBitwiseOr):
(JSC::jsBitwiseXor):
* runtime/Scribble.h: Copied from Source/JavaScriptCore/runtime/BigIntObject.h.
(JSC::scribbleFreeCells):
(JSC::isScribbledValue):
(JSC::scribble):
* runtime/StructureInlines.h:
(JSC::prototypeForLookupPrimitiveImpl):

Source/WTF:

Add a USE(BIGINT32) flag.

* wtf/PlatformUse.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestsstressbigintdivisionjs">trunk/JSTests/stress/big-int-division.js</a></li>
<li><a href="#trunkJSTestsstressbigintleftshiftwrappedvaluejs">trunk/JSTests/stress/big-int-left-shift-wrapped-value.js</a></li>
<li><a href="#trunkJSTestsstressbigintlogicalnotjs">trunk/JSTests/stress/big-int-logical-not.js</a></li>
<li><a href="#trunkJSTestsstressbigintmodjitjs">trunk/JSTests/stress/big-int-mod-jit.js</a></li>
<li><a href="#trunkJSTestsstressbigintmultiplicationjs">trunk/JSTests/stress/big-int-multiplication.js</a></li>
<li><a href="#trunkJSTestsstressbigintrightshiftgeneraljs">trunk/JSTests/stress/big-int-right-shift-general.js</a></li>
<li><a href="#trunkJSTestsstressbiginttypeofproventypejs">trunk/JSTests/stress/big-int-type-of-proven-type.js</a></li>
<li><a href="#trunkJSTestsstresscomparenumberandotherjs">trunk/JSTests/stress/compare-number-and-other.js</a></li>
<li><a href="#trunkJSTestsstresscomparestricteqonvarioustypesjs">trunk/JSTests/stress/compare-strict-eq-on-various-types.js</a></li>
<li><a href="#trunkJSTestsstressftlstringstrictequalityjs">trunk/JSTests/stress/ftl-string-strict-equality.js</a></li>
<li><a href="#trunkJSTestsstressmissingexceptioncheckinstringcomparejs">trunk/JSTests/stress/missing-exception-check-in-string-compare.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerX86Assemblerh">trunk/Source/JavaScriptCore/assembler/X86Assembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeArithProfilecpp">trunk/Source/JavaScriptCore/bytecode/ArithProfile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeArithProfileh">trunk/Source/JavaScriptCore/bytecode/ArithProfile.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeListrb">trunk/Source/JavaScriptCore/bytecode/BytecodeList.rb</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeLivenessAnalysisInlinesh">trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysisInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeUseDefcpp">trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeDataFormath">trunk/Source/JavaScriptCore/bytecode/DataFormat.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeMethodOfGettingAValueProfilecpp">trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeMethodOfGettingAValueProfileh">trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeSpeculatedTypecpp">trunk/Source/JavaScriptCore/bytecode/SpeculatedType.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeSpeculatedTypeh">trunk/Source/JavaScriptCore/bytecode/SpeculatedType.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCapabilitiescpp">trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDoesGCcpp">trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphcpp">trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGMayExitcpp">trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeFlagsh">trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOSRExitcpp">trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationscpp">trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationsh">trunk/Source/JavaScriptCore/dfg/DFGOperations.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITh">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGStrengthReductionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGUseKindcpp">trunk/Source/JavaScriptCore/dfg/DFGUseKind.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGUseKindh">trunk/Source/JavaScriptCore/dfg/DFGUseKind.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCommonValuescpp">trunk/Source/JavaScriptCore/ftl/FTLCommonValues.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCommonValuesh">trunk/Source/JavaScriptCore/ftl/FTLCommonValues.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOSRExitCompilercpp">trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapSnapshotBuildercpp">trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMarkedBlockInlinesh">trunk/Source/JavaScriptCore/heap/MarkedBlockInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapPreciseAllocationcpp">trunk/Source/JavaScriptCore/heap/PreciseAllocation.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectoragentsInspectorHeapAgentcpp">trunk/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterInterpretercpp">trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelperscpp">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelpersh">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITcpp">trunk/Source/JavaScriptCore/jit/JIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITh">trunk/Source/JavaScriptCore/jit/JIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITArithmeticcpp">trunk/Source/JavaScriptCore/jit/JITArithmetic.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodescpp">trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOpcodes32_64cpp">trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationscpp">trunk/Source/JavaScriptCore/jit/JITOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITOperationsh">trunk/Source/JavaScriptCore/jit/JITOperations.h</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLLIntOfflineAsmConfigh">trunk/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreterasm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParserArenacpp">trunk/Source/JavaScriptCore/parser/ParserArena.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeArrayPrototypecpp">trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeBigIntConstructorcpp">trunk/Source/JavaScriptCore/runtime/BigIntConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeBigIntObjectcpp">trunk/Source/JavaScriptCore/runtime/BigIntObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeBigIntObjecth">trunk/Source/JavaScriptCore/runtime/BigIntObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeBigIntPrototypecpp">trunk/Source/JavaScriptCore/runtime/BigIntPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeCommonSlowPathscpp">trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeIntlNumberFormatPrototypecpp">trunk/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSBigIntcpp">trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSBigInth">trunk/Source/JavaScriptCore/runtime/JSBigInt.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCJSValuecpp">trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCJSValueh">trunk/Source/JavaScriptCore/runtime/JSCJSValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCJSValueInlinesh">trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCellcpp">trunk/Source/JavaScriptCore/runtime/JSCell.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCellh">trunk/Source/JavaScriptCore/runtime/JSCell.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCellInlinesh">trunk/Source/JavaScriptCore/runtime/JSCellInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSGlobalObjecth">trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSStringh">trunk/Source/JavaScriptCore/runtime/JSString.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSTypecpp">trunk/Source/JavaScriptCore/runtime/JSType.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSTypeh">trunk/Source/JavaScriptCore/runtime/JSType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSTypeInfoh">trunk/Source/JavaScriptCore/runtime/JSTypeInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeObjectInitializationScopecpp">trunk/Source/JavaScriptCore/runtime/ObjectInitializationScope.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOperationscpp">trunk/Source/JavaScriptCore/runtime/Operations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOperationsh">trunk/Source/JavaScriptCore/runtime/Operations.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureInlinesh">trunk/Source/JavaScriptCore/runtime/StructureInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMcpp">trunk/Source/JavaScriptCore/runtime/VM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMh">trunk/Source/JavaScriptCore/runtime/VM.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretoolsJSDollarVMcpp">trunk/Source/JavaScriptCore/tools/JSDollarVM.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfPlatformUseh">trunk/Source/WTF/wtf/PlatformUse.h</a></li>
<li><a href="#trunkToolsScriptsrunjscstresstests">trunk/Tools/Scripts/run-jsc-stress-tests</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreruntimeScribbleh">trunk/Source/JavaScriptCore/runtime/Scribble.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/ChangeLog     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2020-04-18  Robin Morisset  <rmorisset@apple.com>
+
+        Support an inlined representation in JSValue of small BigInts ("BigInt32")
+        https://bugs.webkit.org/show_bug.cgi?id=206182
+
+        Reviewed by Yusuke Suzuki.
+
+        I improved several of the tests to give more informative error messages in the process of fixing them.
+
+        More interestingly I had to modify "missing-exception-check-in-string-compare" because it relied on "s1 == s1" resolving ropes, and we now just return true.
+
+        * stress/big-int-division.js:
+        (testDiv):
+        * stress/big-int-left-shift-wrapped-value.js:
+        (assert.sameValue):
+        * stress/big-int-logical-not.js:
+        (assert):
+        * stress/big-int-mod-jit.js:
+        * stress/big-int-right-shift-general.js:
+        (testRightShift):
+        * stress/big-int-type-of-proven-type.js:
+        (assert):
+        * stress/compare-strict-eq-on-various-types.js:
+        (testAllTypesCall):
+        * stress/ftl-string-strict-equality.js:
+        * stress/missing-exception-check-in-string-compare.js:
+
</ins><span class="cx"> 2020-04-18  Keith Miller  <keith_miller@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Redesign how we do for-of iteration for JSArrays
</span></span></pre></div>
<a id="trunkJSTestsstressbigintdivisionjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/big-int-division.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/big-int-division.js 2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/big-int-division.js    2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,4 +1,5 @@
</span><span class="cx"> //@ runBigIntEnabled
</span><ins>+//@ runBigIntEnabledNoJIT
</ins><span class="cx"> 
</span><span class="cx"> // Copyright (C) 2017 Robin Templeton. All rights reserved.
</span><span class="cx"> // This code is governed by the BSD license found in the LICENSE file.
</span><span class="lines">@@ -14,7 +15,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> function testDiv(x, y, z) {
</span><del>-    assert.sameValue(x / y, z, x + " / " + y + " = " + z);
</del><ins>+    assert.sameValue(x / y, z, x + " / " + y + " = " + (x/y) + " but should be " + z);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> testDiv(0xFEDCBA9876543210n, 0xFEDCBA9876543210n, 0x1n);
</span></span></pre></div>
<a id="trunkJSTestsstressbigintleftshiftwrappedvaluejs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/big-int-left-shift-wrapped-value.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/big-int-left-shift-wrapped-value.js 2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/big-int-left-shift-wrapped-value.js    2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> assert = {
</span><span class="cx">     sameValue: function (input, expected, message) {
</span><span class="cx">         if (input !== expected)
</span><del>-            throw new Error(message);
</del><ins>+            throw new Error(message + " input: " + input + " != expected: " + expected);
</ins><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJSTestsstressbigintlogicalnotjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/big-int-logical-not.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/big-int-logical-not.js      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/big-int-logical-not.js 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,8 +1,8 @@
</span><span class="cx"> //@ runBigIntEnabled
</span><span class="cx"> 
</span><del>-function assert(a, e) {
</del><ins>+function assert(a, e, n) {
</ins><span class="cx">     if (a !== e) {
</span><del>-        throw new Error("Bad!");
</del><ins>+        throw new Error("Bad logical negation for " + n);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -12,9 +12,9 @@
</span><span class="cx"> noInline(logicalNot);
</span><span class="cx"> 
</span><span class="cx"> for (let i = 0; i < 100000; i++) {
</span><del>-    assert(logicalNot(10n), false);
-    assert(logicalNot(1n), false);
-    assert(logicalNot(0n), true);
-    assert(logicalNot(-1n), false);
</del><ins>+    assert(logicalNot(10n), false, 10n);
+    assert(logicalNot(1n), false, 1n);
+    assert(logicalNot(0n), true, 0n);
+    assert(logicalNot(-1n), false, -1n);
</ins><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJSTestsstressbigintmodjitjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/big-int-mod-jit.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/big-int-mod-jit.js  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/big-int-mod-jit.js     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -25,9 +25,9 @@
</span><span class="cx"> 
</span><span class="cx"> for (let i = 0; i < 10000; i++) {
</span><span class="cx">     let r = bigIntModFolding(10, 30);
</span><del>-    assert.sameValue(r, -10, "-(" + 10 + " % " + 30 + ") = " + r);
</del><ins>+    assert.sameValue(r, -10, "[Number] -(" + 10 + " % " + 30 + ") = " + r);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> let r = bigIntModFolding(10n, 30n);
</span><del>-assert.sameValue(r, -10n, "-(" + 10n + " % " + 30n + ") = " + r);
</del><ins>+assert.sameValue(r, -10n, "[BigInt] -(" + 10n + " % " + 30n + ") = " + r);
</ins><span class="cx"> 
</span></span></pre></div>
<a id="trunkJSTestsstressbigintmultiplicationjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/big-int-multiplication.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/big-int-multiplication.js   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/big-int-multiplication.js      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,18 +1,18 @@
</span><span class="cx"> //@ runBigIntEnabled
</span><ins>+//@ runBigIntEnabledNoJIT
</ins><span class="cx"> 
</span><span class="cx"> // Copyright (C) 2017 Robin Templeton. All rights reserved.
</span><span class="cx"> // This code is governed by the BSD license found in the LICENSE file.
</span><span class="cx"> 
</span><del>-assert = {
-    sameValue: function (input, expected, message) {
-    if (input !== expected)
-        throw new Error(message);
-    }
-};
</del><ins>+function testOneMul(x, y, z) {
+    let result = x * y;
+    if (result !== z)
+        throw new Error("Computing " + x + " * " + y + " resulted in " + result + " instead of the expected " + z);
+}
</ins><span class="cx"> 
</span><span class="cx"> function testMul(x, y, z) {
</span><del>-    assert.sameValue(x * y, z, x + " * " + y + " = " + z);
-    assert.sameValue(y * x, z, y + " * " + x + " = " + z);
</del><ins>+    testOneMul(x, y, z);
+    testOneMul(y, x, z);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> testMul(0xFEDCBA9876543210n, 0xFEDCBA9876543210n, 0xFDBAC097C8DC5ACCDEEC6CD7A44A4100n);
</span></span></pre></div>
<a id="trunkJSTestsstressbigintrightshiftgeneraljs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/big-int-right-shift-general.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/big-int-right-shift-general.js      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/big-int-right-shift-general.js 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,104 +1,63 @@
</span><span class="cx"> //@ runBigIntEnabled
</span><span class="cx"> 
</span><span class="cx"> // Copyright (C) 2017 Josh Wolfe. All rights reserved.
</span><ins>+// Copyright (C) 2020 Apple. All rights reserved
</ins><span class="cx"> // This code is governed by the BSD license found in the LICENSE file.
</span><span class="cx"> 
</span><del>-function assert(a) {
-    if (!a)
-        throw new Error("Bad assertion");
</del><ins>+function testRightShift(left, right, expected)
+{
+    var result = left >> right;
+    if (result !== expected)
+        throw new Error("" + left + ", " + right + " resulted in " + result + " but expected " + expected);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-assert.sameValue = function (input, expected, message) {
-    if (input !== expected)
-        throw new Error(message);
</del><ins>+for (var i = 0; i < 1000 ; ++i) {
+    testRightShift(0n, 0n, 0n);
+    testRightShift(0b101n, -1n, 0b1010n);
+    testRightShift(0b101n, -2n, 0b10100n);
+    testRightShift(0b101n, -3n, 0b101000n);
+    testRightShift(0b101n, 1n, 0b10n);
+    testRightShift(0b101n, 2n, 1n);
+    testRightShift(0b101n, 3n, 0n);
+    testRightShift(0n, -128n, 0n);
+    testRightShift(0n, 128n, 0n);
+    testRightShift(0x246n, 0n, 0x246n);
+    testRightShift(0x246n, -127n, 0x12300000000000000000000000000000000n);
+    testRightShift(0x246n, -128n, 0x24600000000000000000000000000000000n);
+    testRightShift(0x246n, -129n, 0x48c00000000000000000000000000000000n);
+    testRightShift(0x246n, 128n, 0n);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, -64n, 0x123456789abcdef0fedcba98765432123456780000000000000000n);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, -32n, 0x123456789abcdef0fedcba987654321234567800000000n);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, -16n, 0x123456789abcdef0fedcba98765432123456780000n);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, 0n, 0x123456789abcdef0fedcba9876543212345678n);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, 16n, 0x123456789abcdef0fedcba987654321234n);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, 32n, 0x123456789abcdef0fedcba98765432n);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, 64n, 0x123456789abcdef0fedcban);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, 127n, 0x2468acn);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, 128n, 0x123456n);
+    testRightShift(0x123456789abcdef0fedcba9876543212345678n, 129n, 0x91a2bn);
+    testRightShift(-5n, -1n, -0xan);
+    testRightShift(-5n, -2n, -0x14n);
+    testRightShift(-5n, -3n, -0x28n);
+    testRightShift(-5n, 1n, -3n);
+    testRightShift(-5n, 2n, -2n);
+    testRightShift(-5n, 3n, -1n);
+    testRightShift(-1n, -128n, -0x100000000000000000000000000000000n);
+    testRightShift(-1n, 0n, -1n);
+    testRightShift(-1n, 128n, -1n);
+    testRightShift(-0x246n, 0n, -0x246n);
+    testRightShift(-0x246n, -127n, -0x12300000000000000000000000000000000n);
+    testRightShift(-0x246n, -128n, -0x24600000000000000000000000000000000n);
+    testRightShift(-0x246n, -129n, -0x48c00000000000000000000000000000000n);
+    testRightShift(-0x246n, 128n, -1n);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, -64n, -0x123456789abcdef0fedcba98765432123456780000000000000000n);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, -32n, -0x123456789abcdef0fedcba987654321234567800000000n);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, -16n, -0x123456789abcdef0fedcba98765432123456780000n);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, 0n, -0x123456789abcdef0fedcba9876543212345678n);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, 16n, -0x123456789abcdef0fedcba987654321235n);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, 32n, -0x123456789abcdef0fedcba98765433n);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, 64n, -0x123456789abcdef0fedcbbn);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, 127n, -0x2468adn);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, 128n, -0x123457n);
+    testRightShift(-0x123456789abcdef0fedcba9876543212345678n, 129n, -0x91a2cn);
</ins><span class="cx"> }
</span><del>-
-assert.sameValue(0n >> 0n, 0n, "0n >> 0n === 0n");
-assert.sameValue(0b101n >> -1n, 0b1010n, "0b101n >> -1n === 0b1010n");
-assert.sameValue(0b101n >> -2n, 0b10100n, "0b101n >> -2n === 0b10100n");
-assert.sameValue(0b101n >> -3n, 0b101000n, "0b101n >> -3n === 0b101000n");
-assert.sameValue(0b101n >> 1n, 0b10n, "0b101n >> 1n === 0b10n");
-assert.sameValue(0b101n >> 2n, 1n, "0b101n >> 2n === 1n");
-assert.sameValue(0b101n >> 3n, 0n, "0b101n >> 3n === 0n");
-assert.sameValue(0n >> -128n, 0n, "0n >> -128n === 0n");
-assert.sameValue(0n >> 128n, 0n, "0n >> 128n === 0n");
-assert.sameValue(0x246n >> 0n, 0x246n, "0x246n >> 0n === 0x246n");
-assert.sameValue(0x246n >> -127n, 0x12300000000000000000000000000000000n, "0x246n >> -127n === 0x12300000000000000000000000000000000n");
-assert.sameValue(0x246n >> -128n, 0x24600000000000000000000000000000000n, "0x246n >> -128n === 0x24600000000000000000000000000000000n");
-assert.sameValue(0x246n >> -129n, 0x48c00000000000000000000000000000000n, "0x246n >> -129n === 0x48c00000000000000000000000000000000n");
-assert.sameValue(0x246n >> 128n, 0n, "0x246n >> 128n === 0n");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> -64n, 0x123456789abcdef0fedcba98765432123456780000000000000000n,
-  "0x123456789abcdef0fedcba9876543212345678n >> -64n === 0x123456789abcdef0fedcba98765432123456780000000000000000n");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> -32n, 0x123456789abcdef0fedcba987654321234567800000000n,
-  "0x123456789abcdef0fedcba9876543212345678n >> -32n === 0x123456789abcdef0fedcba987654321234567800000000n");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> -16n, 0x123456789abcdef0fedcba98765432123456780000n,
-  "0x123456789abcdef0fedcba9876543212345678n >> -16n === 0x123456789abcdef0fedcba98765432123456780000n");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> 0n, 0x123456789abcdef0fedcba9876543212345678n,
-  "0x123456789abcdef0fedcba9876543212345678n >> 0n === 0x123456789abcdef0fedcba9876543212345678n");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> 16n, 0x123456789abcdef0fedcba987654321234n,
-  "0x123456789abcdef0fedcba9876543212345678n >> 16n === 0x123456789abcdef0fedcba987654321234n");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> 32n, 0x123456789abcdef0fedcba98765432n,
-  "0x123456789abcdef0fedcba9876543212345678n >> 32n === 0x123456789abcdef0fedcba98765432n");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> 64n, 0x123456789abcdef0fedcban,
-  "0x123456789abcdef0fedcba9876543212345678n >> 64n === 0x123456789abcdef0fedcban");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> 127n, 0x2468acn,
-  "0x123456789abcdef0fedcba9876543212345678n >> 127n === 0x2468acn");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> 128n, 0x123456n,
-  "0x123456789abcdef0fedcba9876543212345678n >> 128n === 0x123456n");
-assert.sameValue(
-  0x123456789abcdef0fedcba9876543212345678n >> 129n, 0x91a2bn,
-  "0x123456789abcdef0fedcba9876543212345678n >> 129n === 0x91a2bn");
-assert.sameValue(-5n >> -1n, -0xan, "-5n >> -1n === -0xan");
-assert.sameValue(-5n >> -2n, -0x14n, "-5n >> -2n === -0x14n");
-assert.sameValue(-5n >> -3n, -0x28n, "-5n >> -3n === -0x28n");
-assert.sameValue(-5n >> 1n, -3n, "-5n >> 1n === -3n");
-assert.sameValue(-5n >> 2n, -2n, "-5n >> 2n === -2n");
-assert.sameValue(-5n >> 3n, -1n, "-5n >> 3n === -1n");
-assert.sameValue(-1n >> -128n, -0x100000000000000000000000000000000n, "-1n >> -128n === -0x100000000000000000000000000000000n");
-assert.sameValue(-1n >> 0n, -1n, "-1n >> 0n === -1n");
-assert.sameValue(-1n >> 128n, -1n, "-1n >> 128n === -1n");
-assert.sameValue(-0x246n >> 0n, -0x246n, "-0x246n >> 0n === -0x246n");
-assert.sameValue(-0x246n >> -127n, -0x12300000000000000000000000000000000n, "-0x246n >> -127n === -0x12300000000000000000000000000000000n");
-assert.sameValue(-0x246n >> -128n, -0x24600000000000000000000000000000000n, "-0x246n >> -128n === -0x24600000000000000000000000000000000n");
-assert.sameValue(-0x246n >> -129n, -0x48c00000000000000000000000000000000n, "-0x246n >> -129n === -0x48c00000000000000000000000000000000n");
-assert.sameValue(-0x246n >> 128n, -1n, "-0x246n >> 128n === -1n");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> -64n, -0x123456789abcdef0fedcba98765432123456780000000000000000n,
-  "-0x123456789abcdef0fedcba9876543212345678n >> -64n === -0x123456789abcdef0fedcba98765432123456780000000000000000n");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> -32n, -0x123456789abcdef0fedcba987654321234567800000000n,
-  "-0x123456789abcdef0fedcba9876543212345678n >> -32n === -0x123456789abcdef0fedcba987654321234567800000000n");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> -16n, -0x123456789abcdef0fedcba98765432123456780000n,
-  "-0x123456789abcdef0fedcba9876543212345678n >> -16n === -0x123456789abcdef0fedcba98765432123456780000n");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> 0n, -0x123456789abcdef0fedcba9876543212345678n,
-  "-0x123456789abcdef0fedcba9876543212345678n >> 0n === -0x123456789abcdef0fedcba9876543212345678n");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> 16n, -0x123456789abcdef0fedcba987654321235n,
-  "-0x123456789abcdef0fedcba9876543212345678n >> 16n === -0x123456789abcdef0fedcba987654321235n");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> 32n, -0x123456789abcdef0fedcba98765433n,
-  "-0x123456789abcdef0fedcba9876543212345678n >> 32n === -0x123456789abcdef0fedcba98765433n");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> 64n, -0x123456789abcdef0fedcbbn,
-  "-0x123456789abcdef0fedcba9876543212345678n >> 64n === -0x123456789abcdef0fedcbbn");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> 127n, -0x2468adn,
-  "-0x123456789abcdef0fedcba9876543212345678n >> 127n === -0x2468adn");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> 128n, -0x123457n,
-  "-0x123456789abcdef0fedcba9876543212345678n >> 128n === -0x123457n");
-assert.sameValue(
-  -0x123456789abcdef0fedcba9876543212345678n >> 129n, -0x91a2cn,
-  "-0x123456789abcdef0fedcba9876543212345678n >> 129n === -0x91a2cn");
-
</del></span></pre></div>
<a id="trunkJSTestsstressbiginttypeofproventypejs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/big-int-type-of-proven-type.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/big-int-type-of-proven-type.js      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/big-int-type-of-proven-type.js 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,8 +1,8 @@
</span><span class="cx"> //@ runDefault("--useBigInt=true", "--useConcurrentJIT=false")
</span><span class="cx"> 
</span><del>-function assert(a) {
-    if (!a)
-        throw new Error("Bad assertion");
</del><ins>+function assert(input, expected) {
+    if (input !== expected)
+        throw new Error("Bad result: " + input);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> function foo(o) {
</span><span class="lines">@@ -13,6 +13,5 @@
</span><span class="cx"> noInline(foo);
</span><span class="cx"> 
</span><span class="cx"> for (let i = 0; i < 10000; i++) {
</span><del>-    assert(foo(3n) === "3");
</del><ins>+    assert(foo(3n), "3");
</ins><span class="cx"> }
</span><del>-
</del></span></pre></div>
<a id="trunkJSTestsstresscomparenumberandotherjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/compare-number-and-other.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/compare-number-and-other.js 2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/compare-number-and-other.js    2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -59,17 +59,17 @@
</span><span class="cx">             noInline(testMonomorphicRightConstant${testCaseIndex});
</span><span class="cx"> 
</span><span class="cx">             for (let i = 0; i < 500; ++i) {
</span><del>-                if (testMonomorphic${testCaseIndex}(${left}, ${right}) != ${llintResult})
</del><ins>+                if (testMonomorphic${testCaseIndex}(${left}, ${right}) !== ${llintResult})
</ins><span class="cx">                     throw "Failed testMonomorphic${testCaseIndex}(${left}, ${right})";
</span><del>-                if (testMonomorphicLeftConstant${testCaseIndex}(${right}) != ${llintResult})
</del><ins>+                if (testMonomorphicLeftConstant${testCaseIndex}(${right}) !== ${llintResult})
</ins><span class="cx">                     throw "Failed testMonomorphicLeftConstant${testCaseIndex}(${right})";
</span><del>-                if (testMonomorphicRightConstant${testCaseIndex}(${left}) != ${llintResult})
</del><ins>+                if (testMonomorphicRightConstant${testCaseIndex}(${left}) !== ${llintResult})
</ins><span class="cx">                     throw "Failed testMonomorphicLeftConstant${testCaseIndex}(${left})";
</span><span class="cx">                 if (testPolymorphic(${left}, ${right}) !== ${llintResult})
</span><del>-                    throw "Failed polymorphicVersion(${left})";
</del><ins>+                    throw "Failed polymorphicVersion(${left}, ${operator}, ${right}, expected result: ${llintResult})";
</ins><span class="cx">             }
</span><span class="cx">             `);
</span><span class="cx">             ++testCaseIndex;
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-}
</del><span class="cx">\ No newline at end of file
</span><ins>+}
</ins></span></pre></div>
<a id="trunkJSTestsstresscomparestricteqonvarioustypesjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/compare-strict-eq-on-various-types.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/compare-strict-eq-on-various-types.js       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/compare-strict-eq-on-various-types.js  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -83,7 +83,8 @@
</span><span class="cx">                         ", Right = " +
</span><span class="cx">                         rightCases[rightCaseIndex] +
</span><span class="cx">                         ", Result = " +
</span><del>-                        strictEqualOutput;
</del><ins>+                        strictEqualOutput +
+                        " (case: " + leftCaseIndex + ", " + rightCaseIndex + ")";
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 let strictNotEqualOutput = opaqueStrictNotEqualAllTypes(leftCases[leftCaseIndex], rightCases[rightCaseIndex]);
</span><span class="lines">@@ -93,7 +94,8 @@
</span><span class="cx">                         ", Right = " +
</span><span class="cx">                         rightCases[rightCaseIndex] +
</span><span class="cx">                         ", Result = " +
</span><del>-                        strictEqualOutput;
</del><ins>+                        strictEqualOutput +
+                        " (case: " + leftCaseIndex + ", " + rightCaseIndex + ")";
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkJSTestsstressftlstringstrictequalityjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/ftl-string-strict-equality.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/ftl-string-strict-equality.js       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/ftl-string-strict-equality.js  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -30,6 +30,6 @@
</span><span class="cx">     var result = foo(array, array2[index]);
</span><span class="cx">     var expected = index >= array.length ? null : index
</span><span class="cx">     if (result !== expected)
</span><del>-        throw "Error: bad result: " + result;
</del><ins>+        throw "Error: bad result: " + result + " but expected " + expected;
</ins><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkJSTestsstressmissingexceptioncheckinstringcomparejs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/missing-exception-check-in-string-compare.js (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/missing-exception-check-in-string-compare.js        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/JSTests/stress/missing-exception-check-in-string-compare.js   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,6 +1,8 @@
</span><span class="cx"> const s1 = (-1).toLocaleString().padEnd(2**31-1, 'aa');
</span><ins>+const s2 = (-1).toLocaleString().padEnd(2**31-1, 'aa');
</ins><span class="cx"> try {
</span><del>-    s1 == s1;
</del><ins>+    // Force evaluation of Rope
+    s1 == s2;
</ins><span class="cx"> } catch (e) {
</span><span class="cx">     exception = e;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -986,6 +986,7 @@
</span><span class="cx">     runtime/SamplingProfiler.h
</span><span class="cx">     runtime/ScopeOffset.h
</span><span class="cx">     runtime/ScopedArgumentsTable.h
</span><ins>+    runtime/Scribble.h
</ins><span class="cx">     runtime/ScriptExecutable.h
</span><span class="cx">     runtime/ScriptFetchParameters.h
</span><span class="cx">     runtime/ScriptFetcher.h
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/ChangeLog       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,3 +1,387 @@
</span><ins>+2020-04-18  Robin Morisset  <rmorisset@apple.com>
+
+        Support an inlined representation in JSValue of small BigInts ("BigInt32")
+        https://bugs.webkit.org/show_bug.cgi?id=206182
+
+        Reviewed by Yusuke Suzuki.
+
+        This patch attempts to optimize the performance of BigInts, when they are small (32 bit or less).
+        It works by inlining them into JSValue on 64-bit platforms, avoiding the allocation of a JSBigInt.
+        The bit pattern we use is 0000:XXXX:XXXX:0012
+        This representation works because of the following things:
+        - It cannot be confused with a Double or Integer thanks to the top bits
+        - It cannot be confused with a pointer to a Cell, thanks to bit 1 which is set to true
+        - It cannot be confused with a pointer to wasm thanks to bit 0 which is set to false
+        - It cannot be confused with true/false because bit 2 is set to false
+        - It cannot be confused for null/undefined because bit 4 is set to true
+
+        This entire change is gated by USE(BIGINT32), to make it easier to disable if it turns out to have bugs.
+        It should also make it much easier to verify if a given bug comes from it or from something else.
+
+        Note that in this patch we create BigInt32s when parsing small BigInt constants, and most operations (e.g. Add or BitOr) produce a BigInt32 if both of their operands are BigInt32,
+        but we don't produce a BigInt32 from for example the substraction/division of two large heap-allocated JSBigInts, even if the result fits in 32-bits.
+        As a result, small BigInts can now either be heap-allocated or inlined in the JSValue.
+
+        This patch includes a significant refactor of various slow paths, which are now grouped together in Operations.h
+        Because this increased the size of Operations.h significantly, I split the parts of Operations.h which are only used by the GC into Scribble.h, to avoid bloating compile times.
+
+        In the DFG and FTL we now have 3 UseKinds for BigInts: HeapBigIntUse, BigInt32Use and AnyBigIntUse.
+        The latter is useful when we know that we are receiving BigInts, but speculation indicates a mix of heap-allocated and small (inlined) big-ints.
+
+        Unfortunately, a naive implementation of this patch significantly regresses the performance of StrictEq (and its variants), as it is no longer true that a cell and a non-cell cannot be equal.
+        Before this patch, the code was jumping to a slow path if either:
+        - at least one operand is a double
+        - or both operands are cells
+        Now, it also needs to jump to the slow path if at least one is a cell.
+        To recover this performance cost, I significantly rewrote this code, from
+          if (left is Cell && right is Cell) {
+            if (left == right)
+              return true;
+            goto slowPath;
+          }
+          if (! left is Int32) {
+            if (left is Number)
+              goto slowPath
+          }
+          if (! right is Int32) {
+            if (right is Number)
+              goto slowPath
+          }
+          return left == right
+        To the following:
+          if (left is Double || right is Double)
+            goto slowPath
+          if (left == right)
+            return true;
+          if (left is Cell || right is Cell)
+            goto slowPath
+          return false;
+        I believe this to be faster than just replacing (left is Cell && right is Cell) by an ||, because I found a bit-trick to check (left is Double || right is Double) which should help reduce the pressure on the branch predictor.
+        Early JetStream2 tests appear to confirm that this patch is roughly neutral while it was a 0.5% regression before I used this trick, but the numbers are still too noisy, I plan to do more measurements before landing this patch.
+
+        I don't yet have performance numbers for this patch on a BigInt benchmark, I will get such numbers before trying to land it, but I'd like some review in the meantime.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::X86InstructionFormatter::SingleInstructionBufferWriter::memoryModRM):
+        * bytecode/ArithProfile.cpp:
+        (JSC::ArithProfile<BitfieldType>::emitObserveResult):
+        (JSC::ArithProfile<BitfieldType>::shouldEmitSetBigInt32 const):
+        (JSC::ArithProfile<BitfieldType>::shouldEmitSetHeapBigInt const):
+        (JSC::ArithProfile<BitfieldType>::emitSetHeapBigInt const):
+        (JSC::ArithProfile<BitfieldType>::emitSetBigInt32 const):
+        (WTF::printInternal):
+        * bytecode/ArithProfile.h:
+        (JSC::ObservedResults::didObserveNonInt32):
+        (JSC::ObservedResults::didObserveBigInt):
+        (JSC::ObservedResults::didObserveHeapBigInt):
+        (JSC::ObservedResults::didObserveBigInt32):
+        (JSC::ArithProfile::didObserveHeapBigInt const):
+        (JSC::ArithProfile::didObserveBigInt32 const):
+        (JSC::ArithProfile::setObservedHeapBigInt):
+        (JSC::ArithProfile::setObservedBigInt32):
+        (JSC::ArithProfile::observeResult):
+        * bytecode/BytecodeList.rb:
+        * bytecode/BytecodeLivenessAnalysisInlines.h:
+        * bytecode/BytecodeUseDef.cpp:
+        (JSC::computeUsesForBytecodeIndexImpl):
+        (JSC::computeDefsForBytecodeIndexImpl):
+        * bytecode/CodeBlock.cpp:
+        * bytecode/DataFormat.h:
+        * bytecode/MethodOfGettingAValueProfile.cpp:
+        (JSC::MethodOfGettingAValueProfile::emitReportValue const):
+        * bytecode/MethodOfGettingAValueProfile.h:
+        * bytecode/SpeculatedType.cpp:
+        (JSC::dumpSpeculation):
+        (JSC::speculationFromClassInfo):
+        (JSC::speculationFromStructure):
+        (JSC::speculationFromValue):
+        (JSC::speculationFromJSType):
+        (JSC::leastUpperBoundOfStrictlyEquivalentSpeculations):
+        * bytecode/SpeculatedType.h:
+        (JSC::isBigInt32Speculation):
+        (JSC::isHeapBigIntSpeculation):
+        (JSC::isBigIntSpeculation):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitEqualityOpImpl):
+        (JSC::BytecodeGenerator::addBigIntConstant):
+        * bytecompiler/BytecodeGenerator.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::isToThisAnIdentity):
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixupToThis):
+        (JSC::DFG::FixupPhase::fixupToNumeric):
+        (JSC::DFG::FixupPhase::observeUseKindOnNode):
+        (JSC::DFG::FixupPhase::fixupCompareStrictEqAndSameValue):
+        * dfg/DFGMayExit.cpp:
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::shouldSpeculateBigInt32):
+        (JSC::DFG::Node::shouldSpeculateHeapBigInt):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOSRExit.cpp:
+        (JSC::DFG::OSRExit::compileExit):
+        * dfg/DFGOSRExit.h:
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::SafeToExecuteEdge::operator()):
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleBranch):
+        (JSC::DFG::SpeculativeJIT::compileValueBitNot):
+        (JSC::DFG::SpeculativeJIT::emitUntypedOrAnyBigIntBitOp):
+        (JSC::DFG::SpeculativeJIT::compileValueBitwiseOp):
+        (JSC::DFG::SpeculativeJIT::emitUntypedOrBigIntRightShiftBitOp):
+        (JSC::DFG::SpeculativeJIT::compileValueLShiftOp):
+        (JSC::DFG::SpeculativeJIT::compileValueBitRShift):
+        (JSC::DFG::SpeculativeJIT::compileShiftOp):
+        (JSC::DFG::SpeculativeJIT::compileValueAdd):
+        (JSC::DFG::SpeculativeJIT::compileValueSub):
+        (JSC::DFG::SpeculativeJIT::compileIncOrDec):
+        (JSC::DFG::SpeculativeJIT::compileValueNegate):
+        (JSC::DFG::SpeculativeJIT::compileValueMul):
+        (JSC::DFG::SpeculativeJIT::compileValueDiv):
+        (JSC::DFG::SpeculativeJIT::compileValueMod):
+        (JSC::DFG::SpeculativeJIT::compileValuePow):
+        (JSC::DFG::SpeculativeJIT::compare):
+        (JSC::DFG::SpeculativeJIT::compileStrictEq):
+        (JSC::DFG::SpeculativeJIT::speculateHeapBigInt):
+        (JSC::DFG::SpeculativeJIT::speculate):
+        (JSC::DFG::SpeculativeJIT::compileToNumeric):
+        (JSC::DFG::SpeculativeJIT::compileHeapBigIntEquality):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculateBigInt32Operand::SpeculateBigInt32Operand):
+        (JSC::DFG::SpeculateBigInt32Operand::~SpeculateBigInt32Operand):
+        (JSC::DFG::SpeculateBigInt32Operand::edge const):
+        (JSC::DFG::SpeculateBigInt32Operand::node const):
+        (JSC::DFG::SpeculateBigInt32Operand::gpr):
+        (JSC::DFG::SpeculateBigInt32Operand::use):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::fillJSValue):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeStrictEq):
+        (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateInt32Internal):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
+        (JSC::DFG::SpeculativeJIT::speculateBigInt32):
+        (JSC::DFG::SpeculativeJIT::speculateAnyBigInt):
+        (JSC::DFG::SpeculativeJIT::fillSpeculateBigInt32):
+        (JSC::DFG::SpeculativeJIT::compileBigInt32Compare):
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleBigInt32Branch):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStrengthReductionPhase.cpp:
+        (JSC::DFG::StrengthReductionPhase::handleNode):
+        * dfg/DFGUseKind.cpp:
+        (WTF::printInternal):
+        * dfg/DFGUseKind.h:
+        (JSC::DFG::typeFilterFor):
+        (JSC::DFG::isCell):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLCommonValues.cpp:
+        (JSC::FTL::CommonValues::initializeConstants):
+        * ftl/FTLCommonValues.h:
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueAdd):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueSub):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueMul):
+        (JSC::FTL::DFG::LowerDFGToB3::compileBinaryMathIC):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueDiv):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueMod):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValuePow):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueBitNot):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueBitAnd):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueBitOr):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueBitXor):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueBitRShift):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithBitRShift):
+        (JSC::FTL::DFG::LowerDFGToB3::compileArithBitLShift):
+        (JSC::FTL::DFG::LowerDFGToB3::compileValueBitLShift):
+        (JSC::FTL::DFG::LowerDFGToB3::compileBitURShift):
+        (JSC::FTL::DFG::LowerDFGToB3::compileToNumeric):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareEq):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+        (JSC::FTL::DFG::LowerDFGToB3::compileIsBigInt):
+        (JSC::FTL::DFG::LowerDFGToB3::emitBinarySnippet):
+        (JSC::FTL::DFG::LowerDFGToB3::emitBinaryBitOpSnippet):
+        (JSC::FTL::DFG::LowerDFGToB3::boolify):
+        (JSC::FTL::DFG::LowerDFGToB3::buildTypeOf):
+        (JSC::FTL::DFG::LowerDFGToB3::lowHeapBigInt):
+        (JSC::FTL::DFG::LowerDFGToB3::lowBigInt32):
+        (JSC::FTL::DFG::LowerDFGToB3::isBigInt32):
+        (JSC::FTL::DFG::LowerDFGToB3::isNotBigInt32):
+        (JSC::FTL::DFG::LowerDFGToB3::unboxBigInt32):
+        (JSC::FTL::DFG::LowerDFGToB3::boxBigInt32):
+        (JSC::FTL::DFG::LowerDFGToB3::isNotAnyBigInt):
+        (JSC::FTL::DFG::LowerDFGToB3::speculate):
+        (JSC::FTL::DFG::LowerDFGToB3::isNotHeapBigIntUnknownWhetherCell):
+        (JSC::FTL::DFG::LowerDFGToB3::isNotHeapBigInt):
+        (JSC::FTL::DFG::LowerDFGToB3::isHeapBigInt):
+        (JSC::FTL::DFG::LowerDFGToB3::speculateHeapBigInt):
+        (JSC::FTL::DFG::LowerDFGToB3::speculateHeapBigIntUnknownWhetherCell):
+        (JSC::FTL::DFG::LowerDFGToB3::speculateBigInt32):
+        (JSC::FTL::DFG::LowerDFGToB3::speculateAnyBigInt):
+        * ftl/FTLOSRExitCompiler.cpp:
+        (JSC::FTL::compileStub):
+        * heap/HeapSnapshotBuilder.cpp:
+        (JSC::HeapSnapshotBuilder::json):
+        * heap/MarkedBlockInlines.h:
+        * heap/PreciseAllocation.cpp:
+        * inspector/agents/InspectorHeapAgent.cpp:
+        (Inspector::InspectorHeapAgent::getPreview):
+        * interpreter/Interpreter.cpp:
+        (JSC::sizeOfVarargs):
+        * jit/AssemblyHelpers.cpp:
+        (JSC::AssemblyHelpers::emitConvertValueToBoolean):
+        (JSC::AssemblyHelpers::branchIfValue):
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::branchIfBigInt32):
+        (JSC::AssemblyHelpers::branchIfBigInt32KnownNotNumber):
+        (JSC::AssemblyHelpers::branchIfNotBigInt32KnownNotNumber):
+        (JSC::AssemblyHelpers::branchIfHeapBigInt):
+        (JSC::AssemblyHelpers::branchIfNotHeapBigInt):
+        (JSC::AssemblyHelpers::unboxBigInt32):
+        (JSC::AssemblyHelpers::boxBigInt32):
+        (JSC::AssemblyHelpers::emitTypeOf):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITArithmetic.cpp:
+        (JSC::JIT::emit_op_negate):
+        (JSC::JIT::emitSlow_op_negate):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_is_big_int):
+        (JSC::JIT::compileOpStrictEq):
+        (JSC::JIT::compileOpStrictEqJump):
+        (JSC::JIT::emit_op_to_numeric):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_is_big_int):
+        (JSC::JIT::emit_op_to_numeric):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * llint/LLIntOfflineAsmConfig.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * parser/ParserArena.cpp:
+        (JSC::IdentifierArena::makeBigIntDecimalIdentifier):
+        * runtime/ArrayPrototype.cpp:
+        * runtime/BigIntConstructor.cpp:
+        (JSC::toBigInt):
+        (JSC::callBigIntConstructor):
+        * runtime/BigIntObject.cpp:
+        (JSC::BigIntObject::create):
+        (JSC::BigIntObject::finishCreation):
+        * runtime/BigIntObject.h:
+        * runtime/BigIntPrototype.cpp:
+        (JSC::toThisBigIntValue):
+        (JSC::bigIntProtoFuncToStringImpl):
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        (JSC::updateArithProfileForUnaryArithOp):
+        (JSC::updateArithProfileForBinaryArithOp):
+        * runtime/JSBigInt.cpp:
+        (JSC::JSBigInt::createStructure):
+        (JSC::JSBigInt::parseInt):
+        (JSC::JSBigInt::stringToBigInt):
+        (JSC::JSBigInt::inc):
+        (JSC::JSBigInt::dec):
+        (JSC::JSBigInt::bitwiseAnd):
+        (JSC::JSBigInt::toStringGeneric):
+        (JSC::JSBigInt::equalsToNumber):
+        (JSC::JSBigInt::equalsToInt32):
+        * runtime/JSBigInt.h:
+        (JSC::asHeapBigInt):
+        * runtime/JSCJSValue.cpp:
+        (JSC::JSValue::toNumberSlowCase const):
+        (JSC::JSValue::toObjectSlowCase const):
+        (JSC::JSValue::toThisSlowCase const):
+        (JSC::JSValue::synthesizePrototype const):
+        (JSC::JSValue::dumpInContextAssumingStructure const):
+        (JSC::JSValue::dumpForBacktrace const):
+        (JSC::JSValue::toStringSlowCase const):
+        * runtime/JSCJSValue.h:
+        * runtime/JSCJSValueInlines.h:
+        (JSC::JSValue::JSValue):
+        (JSC::JSValue::asHeapBigInt const):
+        (JSC::JSValue::isBigInt const):
+        (JSC::JSValue::isHeapBigInt const):
+        (JSC::JSValue::isBigInt32 const):
+        (JSC::JSValue::bigInt32AsInt32 const):
+        (JSC::JSValue::isPrimitive const):
+        (JSC::JSValue::getPrimitiveNumber):
+        (JSC::JSValue::toNumeric const):
+        (JSC::JSValue::toBigIntOrInt32 const):
+        (JSC::JSValue::equalSlowCaseInline):
+        (JSC::JSValue::strictEqualForCells):
+        (JSC::JSValue::strictEqual):
+        (JSC::JSValue::pureStrictEqual):
+        (JSC::JSValue::pureToBoolean const):
+        * runtime/JSCell.cpp:
+        (JSC::JSCell::put):
+        (JSC::JSCell::putByIndex):
+        (JSC::JSCell::toPrimitive const):
+        (JSC::JSCell::getPrimitiveNumber const):
+        (JSC::JSCell::toNumber const):
+        (JSC::JSCell::toObjectSlow const):
+        * runtime/JSCell.h:
+        * runtime/JSCellInlines.h:
+        (JSC::JSCell::isHeapBigInt const):
+        (JSC::JSCell::toBoolean const):
+        (JSC::JSCell::pureToBoolean const):
+        * runtime/JSString.h:
+        (JSC::JSValue::toBoolean const):
+        * runtime/JSType.cpp:
+        (WTF::printInternal):
+        * runtime/JSType.h:
+        * runtime/JSTypeInfo.h:
+        * runtime/ObjectInitializationScope.cpp:
+        * runtime/Operations.cpp:
+        (JSC::jsAddSlowCase):
+        (JSC::jsIsObjectTypeOrNull):
+        * runtime/Operations.h:
+        (JSC::compareBigIntToOtherPrimitive):
+        (JSC::bigIntCompare):
+        (JSC::jsLess):
+        (JSC::jsLessEq):
+        (JSC::arithmeticBinaryOp):
+        (JSC::jsSub):
+        (JSC::jsMul):
+        (JSC::jsDiv):
+        (JSC::jsRemainder):
+        (JSC::jsPow):
+        (JSC::jsInc):
+        (JSC::jsDec):
+        (JSC::jsBitwiseNot):
+        (JSC::shift):
+        (JSC::jsLShift):
+        (JSC::jsRShift):
+        (JSC::bitwiseBinaryOp):
+        (JSC::jsBitwiseAnd):
+        (JSC::jsBitwiseOr):
+        (JSC::jsBitwiseXor):
+        * runtime/Scribble.h: Copied from Source/JavaScriptCore/runtime/BigIntObject.h.
+        (JSC::scribbleFreeCells):
+        (JSC::isScribbledValue):
+        (JSC::scribble):
+        * runtime/StructureInlines.h:
+        (JSC::prototypeForLookupPrimitiveImpl):
+
</ins><span class="cx"> 2020-04-18  Keith Miller  <keith_miller@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, remove commented out/dead code that didn't failed to
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -867,6 +867,7 @@
</span><span class="cx">          2AD8932B17E3868F00668276 /* HeapIterationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AD8932917E3868F00668276 /* HeapIterationScope.h */; };
</span><span class="cx">          2AF7382D18BBBF92008A5A37 /* StructureIDTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 2AF7382B18BBBF92008A5A37 /* StructureIDTable.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          2D342F36F7244096804ADB24 /* SourceOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = 425BA1337E4344E1B269A671 /* SourceOrigin.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+               33111B8B2397256500AA34CE /* Scribble.h in Headers */ = {isa = PBXBuildFile; fileRef = 33111B8A2397256500AA34CE /* Scribble.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">           3395C70722555F6D00BDBFAD /* B3EliminateDeadCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3395C70522555F6D00BDBFAD /* B3EliminateDeadCode.h */; };
</span><span class="cx">          33A920BD23DA2C6D000EBAF0 /* CommonSlowPathsInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 33A920BC23DA2C6D000EBAF0 /* CommonSlowPathsInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          33B2A54722653481005A0F79 /* B3ValueInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FEC84FB1BDACDAC0080FF74 /* B3ValueInlines.h */; };
</span><span class="lines">@@ -3519,6 +3520,7 @@
</span><span class="cx">          2AF7382B18BBBF92008A5A37 /* StructureIDTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureIDTable.h; sourceTree = "<group>"; };
</span><span class="cx">          3032175DF1AD47D8998B34E1 /* JSSourceCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSourceCode.h; sourceTree = "<group>"; };
</span><span class="cx">          30A5F403F11C4F599CD596D5 /* WasmSignatureInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmSignatureInlines.h; sourceTree = "<group>"; };
</span><ins>+               33111B8A2397256500AA34CE /* Scribble.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Scribble.h; sourceTree = "<group>"; };
</ins><span class="cx">           33743649224D79EF00C8C227 /* B3OptimizeAssociativeExpressionTrees.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = B3OptimizeAssociativeExpressionTrees.cpp; path = b3/B3OptimizeAssociativeExpressionTrees.cpp; sourceTree = "<group>"; };
</span><span class="cx">          3374364A224D79EF00C8C227 /* B3OptimizeAssociativeExpressionTrees.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = B3OptimizeAssociativeExpressionTrees.h; path = b3/B3OptimizeAssociativeExpressionTrees.h; sourceTree = "<group>"; };
</span><span class="cx">          3395C70422555F6C00BDBFAD /* B3EliminateDeadCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3EliminateDeadCode.cpp; path = b3/B3EliminateDeadCode.cpp; sourceTree = "<group>"; };
</span><span class="lines">@@ -7582,6 +7584,7 @@
</span><span class="cx">                          0FE050201AA9095600D33B33 /* ScopedArgumentsTable.h */,
</span><span class="cx">                          0FE050211AA9095600D33B33 /* ScopeOffset.cpp */,
</span><span class="cx">                          0FE050221AA9095600D33B33 /* ScopeOffset.h */,
</span><ins>+                               33111B8A2397256500AA34CE /* Scribble.h */,
</ins><span class="cx">                           147341E01DC2CE9600AA29BA /* ScriptExecutable.cpp */,
</span><span class="cx">                          147341CD1DC02D7900AA29BA /* ScriptExecutable.h */,
</span><span class="cx">                          8852151A9C3842389B3215B7 /* ScriptFetcher.h */,
</span><span class="lines">@@ -8954,6 +8957,7 @@
</span><span class="cx">                          0FEC85911BDACDC70080FF74 /* AirValidate.h in Headers */,
</span><span class="cx">                          0FEC3C531F33A41600F59B6C /* AlignedMemoryAllocator.h in Headers */,
</span><span class="cx">                          0FA7620B1DB959F900B7A2FD /* AllocatingScope.h in Headers */,
</span><ins>+                               33111B8B2397256500AA34CE /* Scribble.h in Headers */,
</ins><span class="cx">                           0FDCE11C1FAE6209006F3901 /* AllocationFailureMode.h in Headers */,
</span><span class="cx">                          0F75A063200D261F0038E2CF /* Allocator.h in Headers */,
</span><span class="cx">                          0F30CB5E1FCE4E37004B5323 /* AllocatorForMode.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerX86Assemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/X86Assembler.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/X86Assembler.h     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -4698,7 +4698,7 @@
</span><span class="cx"> 
</span><span class="cx">         // Immediates:
</span><span class="cx">         //
</span><del>-        // An immedaite should be appended where appropriate after an op has been emitted.
</del><ins>+        // An immediate should be appended where appropriate after an op has been emitted.
</ins><span class="cx">         // The writes are unchecked since the opcode formatters above will have ensured space.
</span><span class="cx"> 
</span><span class="cx">         void immediate8(int imm)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeArithProfilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/ArithProfile.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/ArithProfile.cpp    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/ArithProfile.cpp       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2016-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -33,9 +33,9 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> template<typename BitfieldType>
</span><del>-void ArithProfile<BitfieldType>::emitObserveResult(CCallHelpers& jit, JSValueRegs regs, TagRegistersMode mode)
</del><ins>+void ArithProfile<BitfieldType>::emitObserveResult(CCallHelpers& jit, JSValueRegs regs, GPRReg tempGPR, TagRegistersMode mode)
</ins><span class="cx"> {
</span><del>-    if (!shouldEmitSetDouble() && !shouldEmitSetNonNumeric() && !shouldEmitSetBigInt())
</del><ins>+    if (!shouldEmitSetDouble() && !shouldEmitSetNonNumeric() && !shouldEmitSetHeapBigInt() && !shouldEmitSetBigInt32())
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     CCallHelpers::JumpList done;
</span><span class="lines">@@ -48,9 +48,18 @@
</span><span class="cx"> 
</span><span class="cx">     notDouble.link(&jit);
</span><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+    CCallHelpers::Jump notBigInt32 = jit.branchIfNotBigInt32KnownNotNumber(regs, tempGPR);
+    emitSetBigInt32(jit);
+    done.append(jit.jump());
+    notBigInt32.link(&jit);
+#else
+    UNUSED_PARAM(tempGPR);
+#endif
+
</ins><span class="cx">     nonNumeric.append(jit.branchIfNotCell(regs, mode));
</span><del>-    nonNumeric.append(jit.branchIfNotBigInt(regs.payloadGPR()));
-    emitSetBigInt(jit);
</del><ins>+    nonNumeric.append(jit.branchIfNotHeapBigInt(regs.payloadGPR()));
+    emitSetHeapBigInt(jit);
</ins><span class="cx">     done.append(jit.jump());
</span><span class="cx"> 
</span><span class="cx">     nonNumeric.link(&jit);
</span><span class="lines">@@ -88,20 +97,40 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template<typename BitfieldType>
</span><del>-bool ArithProfile<BitfieldType>::shouldEmitSetBigInt() const
</del><ins>+bool ArithProfile<BitfieldType>::shouldEmitSetBigInt32() const
</ins><span class="cx"> {
</span><del>-    BitfieldType mask = ObservedResults::BigInt;
</del><ins>+#if USE(BIGINT32)
+    BitfieldType mask = ObservedResults::BigInt32;
</ins><span class="cx">     return (m_bits & mask) != mask;
</span><ins>+#else
+    return false;
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template<typename BitfieldType>
</span><del>-void ArithProfile<BitfieldType>::emitSetBigInt(CCallHelpers& jit) const
</del><ins>+bool ArithProfile<BitfieldType>::shouldEmitSetHeapBigInt() const
</ins><span class="cx"> {
</span><del>-    if (shouldEmitSetBigInt())
-        emitUnconditionalSet(jit, ObservedResults::BigInt);
</del><ins>+    BitfieldType mask = ObservedResults::HeapBigInt;
+    return (m_bits & mask) != mask;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template<typename BitfieldType>
</span><ins>+void ArithProfile<BitfieldType>::emitSetHeapBigInt(CCallHelpers& jit) const
+{
+    if (shouldEmitSetHeapBigInt())
+        emitUnconditionalSet(jit, ObservedResults::HeapBigInt);
+}
+
+#if USE(BIGINT32)
+template<typename BitfieldType>
+void ArithProfile<BitfieldType>::emitSetBigInt32(CCallHelpers& jit) const
+{
+    if (shouldEmitSetBigInt32())
+        emitUnconditionalSet(jit, ObservedResults::BigInt32);
+}
+#endif
+
+template<typename BitfieldType>
</ins><span class="cx"> void ArithProfile<BitfieldType>::emitUnconditionalSet(CCallHelpers& jit, BitfieldType mask) const
</span><span class="cx"> {
</span><span class="cx">     static_assert(std::is_same<BitfieldType, uint16_t>::value);
</span><span class="lines">@@ -149,10 +178,14 @@
</span><span class="cx">             out.print(separator, "Int52Overflow");
</span><span class="cx">             separator = "|";
</span><span class="cx">         }
</span><del>-        if (profile.didObserveBigInt()) {
-            out.print(separator, "BigInt");
</del><ins>+        if (profile.didObserveHeapBigInt()) {
+            out.print(separator, "HeapBigInt");
</ins><span class="cx">             separator = "|";
</span><span class="cx">         }
</span><ins>+        if (profile.didObserveBigInt32()) {
+            out.print(separator, "BigInt32");
+            separator = "|";
+        }
</ins><span class="cx">     }
</span><span class="cx">     out.print(">");
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeArithProfileh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/ArithProfile.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/ArithProfile.h      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/ArithProfile.h 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2016-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -74,9 +74,10 @@
</span><span class="cx">         NonNumeric       = 1 << 2,
</span><span class="cx">         Int32Overflow    = 1 << 3,
</span><span class="cx">         Int52Overflow    = 1 << 4,
</span><del>-        BigInt           = 1 << 5,
</del><ins>+        HeapBigInt       = 1 << 5,
+        BigInt32         = 1 << 6,
</ins><span class="cx">     };
</span><del>-    static constexpr uint32_t numBitsNeeded = 6;
</del><ins>+    static constexpr uint32_t numBitsNeeded = 7;
</ins><span class="cx"> 
</span><span class="cx">     ObservedResults() = default;
</span><span class="cx">     explicit ObservedResults(uint8_t bits)
</span><span class="lines">@@ -83,12 +84,14 @@
</span><span class="cx">         : m_bits(bits)
</span><span class="cx">     { }
</span><span class="cx"> 
</span><del>-    bool didObserveNonInt32() { return m_bits & (NonNegZeroDouble | NegZeroDouble | NonNumeric | BigInt); }
</del><ins>+    bool didObserveNonInt32() { return m_bits & (NonNegZeroDouble | NegZeroDouble | NonNumeric | HeapBigInt | BigInt32); }
</ins><span class="cx">     bool didObserveDouble() { return m_bits & (NonNegZeroDouble | NegZeroDouble); }
</span><span class="cx">     bool didObserveNonNegZeroDouble() { return m_bits & NonNegZeroDouble; }
</span><span class="cx">     bool didObserveNegZeroDouble() { return m_bits & NegZeroDouble; }
</span><span class="cx">     bool didObserveNonNumeric() { return m_bits & NonNumeric; }
</span><del>-    bool didObserveBigInt() { return m_bits & BigInt; }
</del><ins>+    bool didObserveBigInt() { return m_bits & (HeapBigInt | BigInt32); }
+    bool didObserveHeapBigInt() { return m_bits & HeapBigInt; }
+    bool didObserveBigInt32() { return m_bits & BigInt32; }
</ins><span class="cx">     bool didObserveInt32Overflow() { return m_bits & Int32Overflow; }
</span><span class="cx">     bool didObserveInt52Overflow() { return m_bits & Int52Overflow; }
</span><span class="cx"> 
</span><span class="lines">@@ -109,6 +112,8 @@
</span><span class="cx">     bool didObserveNegZeroDouble() const { return observedResults().didObserveNegZeroDouble(); }
</span><span class="cx">     bool didObserveNonNumeric() const { return observedResults().didObserveNonNumeric(); }
</span><span class="cx">     bool didObserveBigInt() const { return observedResults().didObserveBigInt(); }
</span><ins>+    bool didObserveHeapBigInt() const { return observedResults().didObserveHeapBigInt(); }
+    bool didObserveBigInt32() const { return observedResults().didObserveBigInt32(); }
</ins><span class="cx">     bool didObserveInt32Overflow() const { return observedResults().didObserveInt32Overflow(); }
</span><span class="cx">     bool didObserveInt52Overflow() const { return observedResults().didObserveInt52Overflow(); }
</span><span class="cx"> 
</span><span class="lines">@@ -115,7 +120,8 @@
</span><span class="cx">     void setObservedNonNegZeroDouble() { setBit(ObservedResults::NonNegZeroDouble); }
</span><span class="cx">     void setObservedNegZeroDouble() { setBit(ObservedResults::NegZeroDouble); }
</span><span class="cx">     void setObservedNonNumeric() { setBit(ObservedResults::NonNumeric); }
</span><del>-    void setObservedBigInt() { setBit(ObservedResults::BigInt); }
</del><ins>+    void setObservedHeapBigInt() { setBit(ObservedResults::HeapBigInt); }
+    void setObservedBigInt32() { setBit(ObservedResults::BigInt32); }
</ins><span class="cx">     void setObservedInt32Overflow() { setBit(ObservedResults::Int32Overflow); }
</span><span class="cx">     void setObservedInt52Overflow() { setBit(ObservedResults::Int52Overflow); }
</span><span class="cx"> 
</span><span class="lines">@@ -127,10 +133,14 @@
</span><span class="cx">             m_bits |= ObservedResults::Int32Overflow | ObservedResults::Int52Overflow | ObservedResults::NonNegZeroDouble | ObservedResults::NegZeroDouble;
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        if (value && value.isBigInt()) {
-            m_bits |= ObservedResults::BigInt;
</del><ins>+        if (value.isBigInt32()) {
+            m_bits |= ObservedResults::BigInt32;
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        if (value && value.isHeapBigInt()) {
+            m_bits |= ObservedResults::HeapBigInt;
+            return;
+        }
</ins><span class="cx">         m_bits |= ObservedResults::NonNumeric;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -139,20 +149,23 @@
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx">     // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble) if it sees a
</span><span class="cx">     // double. Sets NonNumeric if it sees a non-numeric.
</span><del>-    void emitObserveResult(CCallHelpers&, JSValueRegs, TagRegistersMode = HaveTagRegisters);
</del><ins>+    void emitObserveResult(CCallHelpers&, JSValueRegs, GPRReg tempGPR, TagRegistersMode = HaveTagRegisters);
</ins><span class="cx"> 
</span><span class="cx">     // Sets (Int32Overflow | Int52Overflow | NonNegZeroDouble | NegZeroDouble).
</span><span class="cx">     bool shouldEmitSetDouble() const;
</span><span class="cx">     void emitSetDouble(CCallHelpers&) const;
</span><span class="cx"> 
</span><del>-    // Sets NonNumeric
</del><span class="cx">     void emitSetNonNumeric(CCallHelpers&) const;
</span><span class="cx">     bool shouldEmitSetNonNumeric() const;
</span><span class="cx"> 
</span><del>-    // Sets BigInt
-    void emitSetBigInt(CCallHelpers&) const;
-    bool shouldEmitSetBigInt() const;
</del><ins>+    bool shouldEmitSetHeapBigInt() const;
+    void emitSetHeapBigInt(CCallHelpers&) const;
</ins><span class="cx"> 
</span><ins>+    bool shouldEmitSetBigInt32() const;
+#if USE(BIGINT32)
+    void emitSetBigInt32(CCallHelpers&) const;
+#endif
+
</ins><span class="cx">     void emitUnconditionalSet(CCallHelpers&, BitfieldType) const;
</span><span class="cx"> #endif // ENABLE(JIT)
</span><span class="cx"> 
</span><span class="lines">@@ -175,7 +188,7 @@
</span><span class="cx"> class UnaryArithProfile : public ArithProfile<UnaryArithProfileBase> {
</span><span class="cx">     static constexpr unsigned argObservedTypeShift = ObservedResults::numBitsNeeded;
</span><span class="cx"> 
</span><del>-    static_assert(argObservedTypeShift + ObservedType::numBitsNeeded <= sizeof(UnaryArithProfileBase) * 8, "Should fit in a the type of the underlying bitfield.");
</del><ins>+    static_assert(argObservedTypeShift + ObservedType::numBitsNeeded <= sizeof(UnaryArithProfileBase) * 8, "Should fit in the type of the underlying bitfield.");
</ins><span class="cx"> 
</span><span class="cx">     static constexpr UnaryArithProfileBase clearArgObservedTypeBitMask = static_cast<UnaryArithProfileBase>(~(0b111 << argObservedTypeShift));
</span><span class="cx"> 
</span><span class="lines">@@ -257,7 +270,7 @@
</span><span class="cx"> 
</span><span class="cx"> public:
</span><span class="cx">     static constexpr BinaryArithProfileBase specialFastPathBit = 1 << (lhsObservedTypeShift + ObservedType::numBitsNeeded);
</span><del>-    static_assert((lhsObservedTypeShift + ObservedType::numBitsNeeded + 1) <= sizeof(BinaryArithProfileBase) * 8, "Should fit in a uint32_t.");
</del><ins>+    static_assert((lhsObservedTypeShift + ObservedType::numBitsNeeded + 1) <= sizeof(BinaryArithProfileBase) * 8, "Should fit in the underlying type.");
</ins><span class="cx">     static_assert(!(specialFastPathBit & ~clearLhsObservedTypeBitMask), "These bits should not intersect.");
</span><span class="cx">     static_assert(specialFastPathBit & clearLhsObservedTypeBitMask, "These bits should intersect.");
</span><span class="cx">     static_assert(static_cast<unsigned>(specialFastPathBit) > static_cast<unsigned>(static_cast<BinaryArithProfileBase>(~clearLhsObservedTypeBitMask)), "These bits should not intersect and specialFastPathBit should be a higher bit.");
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeListrb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeList.rb (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeList.rb     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeList.rb        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -330,6 +330,7 @@
</span><span class="cx">         :is_undefined_or_null,
</span><span class="cx">         :is_boolean,
</span><span class="cx">         :is_number,
</span><ins>+        :is_big_int,
</ins><span class="cx">         :is_object,
</span><span class="cx">         :is_object_or_null,
</span><span class="cx">         :is_function,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeLivenessAnalysisInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysisInlines.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysisInlines.h   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysisInlines.h      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -29,7 +29,6 @@
</span><span class="cx"> #include "BytecodeLivenessAnalysis.h"
</span><span class="cx"> #include "CodeBlock.h"
</span><span class="cx"> #include "InterpreterInlines.h"
</span><del>-#include "Operations.h"
</del><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeUseDefcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -174,6 +174,7 @@
</span><span class="cx">     USES(OpIsUndefinedOrNull, operand)
</span><span class="cx">     USES(OpIsBoolean, operand)
</span><span class="cx">     USES(OpIsNumber, operand)
</span><ins>+    USES(OpIsBigInt, operand)
</ins><span class="cx">     USES(OpIsObject, operand)
</span><span class="cx">     USES(OpIsObjectOrNull, operand)
</span><span class="cx">     USES(OpIsCellWithType, operand)
</span><span class="lines">@@ -426,9 +427,10 @@
</span><span class="cx">     DEFS(OpIdentityWithProfile, srcDst)
</span><span class="cx">     DEFS(OpIsEmpty, dst)
</span><span class="cx">     DEFS(OpIsUndefined, dst)
</span><del>-    USES(OpIsUndefinedOrNull, dst)
</del><ins>+    DEFS(OpIsUndefinedOrNull, dst)
</ins><span class="cx">     DEFS(OpIsBoolean, dst)
</span><span class="cx">     DEFS(OpIsNumber, dst)
</span><ins>+    DEFS(OpIsBigInt, dst)
</ins><span class="cx">     DEFS(OpIsObject, dst)
</span><span class="cx">     DEFS(OpIsObjectOrNull, dst)
</span><span class="cx">     DEFS(OpIsCellWithType, dst)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -61,7 +61,6 @@
</span><span class="cx"> #include "IsoCellSetInlines.h"
</span><span class="cx"> #include "JIT.h"
</span><span class="cx"> #include "JITMathIC.h"
</span><del>-#include "JSBigInt.h"
</del><span class="cx"> #include "JSCInlines.h"
</span><span class="cx"> #include "JSCJSValue.h"
</span><span class="cx"> #include "JSFunction.h"
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeDataFormath"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/DataFormat.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/DataFormat.h        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/DataFormat.h   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -44,12 +44,14 @@
</span><span class="cx">     DataFormatBoolean = 5,
</span><span class="cx">     DataFormatCell = 6,
</span><span class="cx">     DataFormatStorage = 7,
</span><del>-    DataFormatJS = 8,
</del><ins>+    DataFormatBigInt32 = 8, // FIXME: currently unused
+    DataFormatJS = 16,
</ins><span class="cx">     DataFormatJSInt32 = DataFormatJS | DataFormatInt32,
</span><span class="cx">     DataFormatJSDouble = DataFormatJS | DataFormatDouble,
</span><span class="cx">     DataFormatJSCell = DataFormatJS | DataFormatCell,
</span><span class="cx">     DataFormatJSBoolean = DataFormatJS | DataFormatBoolean,
</span><del>-    
</del><ins>+    DataFormatJSBigInt32 = DataFormatJS | DataFormatBigInt32,
+
</ins><span class="cx">     // Marker deliminating ordinary data formats and OSR-only data formats.
</span><span class="cx">     DataFormatOSRMarker = 32, 
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeMethodOfGettingAValueProfilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.cpp       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MethodOfGettingAValueProfile::emitReportValue(CCallHelpers& jit, JSValueRegs regs) const
</del><ins>+void MethodOfGettingAValueProfile::emitReportValue(CCallHelpers& jit, JSValueRegs regs, GPRReg tempGPR, TagRegistersMode mode) const
</ins><span class="cx"> {
</span><span class="cx">     switch (m_kind) {
</span><span class="cx">     case None:
</span><span class="lines">@@ -67,12 +67,12 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case UnaryArithProfileReady: {
</span><del>-        u.unaryArithProfile->emitObserveResult(jit, regs, DoNotHaveTagRegisters);
</del><ins>+        u.unaryArithProfile->emitObserveResult(jit, regs, tempGPR, mode);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case BinaryArithProfileReady: {
</span><del>-        u.binaryArithProfile->emitObserveResult(jit, regs, DoNotHaveTagRegisters);
</del><ins>+        u.binaryArithProfile->emitObserveResult(jit, regs, tempGPR, mode);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeMethodOfGettingAValueProfileh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/MethodOfGettingAValueProfile.h 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> #include "BytecodeIndex.h"
</span><span class="cx"> #include "GPRInfo.h"
</span><span class="cx"> #include "Operands.h"
</span><ins>+#include "TagRegistersMode.h"
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -83,7 +84,8 @@
</span><span class="cx">     
</span><span class="cx">     explicit operator bool() const { return m_kind != None; }
</span><span class="cx"> 
</span><del>-    void emitReportValue(CCallHelpers&, JSValueRegs) const;
</del><ins>+    // The temporary register is only needed on 64-bits builds (for testing BigInt32).
+    void emitReportValue(CCallHelpers&, JSValueRegs, GPRReg tempGPR, TagRegistersMode = HaveTagRegisters) const;
</ins><span class="cx">     void reportValue(JSValue);
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeSpeculatedTypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/SpeculatedType.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/SpeculatedType.cpp  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/SpeculatedType.cpp     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -239,11 +239,6 @@
</span><span class="cx">             strOut.print("Symbol");
</span><span class="cx">         else
</span><span class="cx">             isTop = false;
</span><del>-
-        if (value & SpecBigInt)
-            strOut.print("BigInt");
-        else
-            isTop = false;
</del><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (value == SpecInt32Only)
</span><span class="lines">@@ -278,7 +273,23 @@
</span><span class="cx">         else
</span><span class="cx">             isTop = false;
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    if ((value & SpecBigInt) == SpecBigInt)
+        strOut.print("BigInt");
+#if USE(BIGINT32)
+    else {
+        if (value & SpecBigInt32)
+            strOut.print("BigInt32");
+        else
+            isTop = false;
+
+        if (value & SpecHeapBigInt)
+            strOut.print("HeapBigInt");
+        else
+            isTop = false;
+    }
+#endif
+
</ins><span class="cx">     if (value & SpecDoubleImpureNaN)
</span><span class="cx">         strOut.print("DoubleImpureNaN");
</span><span class="cx">     
</span><span class="lines">@@ -431,7 +442,7 @@
</span><span class="cx">         return SpecSymbol;
</span><span class="cx">     
</span><span class="cx">     if (classInfo == JSBigInt::info())
</span><del>-        return SpecBigInt;
</del><ins>+        return SpecHeapBigInt;
</ins><span class="cx"> 
</span><span class="cx">     if (classInfo == JSFinalObject::info())
</span><span class="cx">         return SpecFinalObject;
</span><span class="lines">@@ -499,8 +510,8 @@
</span><span class="cx">         return SpecString;
</span><span class="cx">     if (structure->typeInfo().type() == SymbolType)
</span><span class="cx">         return SpecSymbol;
</span><del>-    if (structure->typeInfo().type() == BigIntType)
-        return SpecBigInt;
</del><ins>+    if (structure->typeInfo().type() == HeapBigIntType)
+        return SpecHeapBigInt;
</ins><span class="cx">     if (structure->typeInfo().type() == DerivedArrayType)
</span><span class="cx">         return SpecDerivedArray;
</span><span class="cx">     return speculationFromClassInfo(structure->classInfo());
</span><span class="lines">@@ -536,6 +547,8 @@
</span><span class="cx">             return SpecAnyIntAsDouble;
</span><span class="cx">         return SpecNonIntAsDouble;
</span><span class="cx">     }
</span><ins>+    if (value.isBigInt32())
+        return SpecBigInt32;
</ins><span class="cx">     if (value.isCell())
</span><span class="cx">         return speculationFromCell(value.asCell());
</span><span class="cx">     if (value.isBoolean())
</span><span class="lines">@@ -595,8 +608,8 @@
</span><span class="cx">         return SpecString;
</span><span class="cx">     case SymbolType:
</span><span class="cx">         return SpecSymbol;
</span><del>-    case BigIntType:
-        return SpecBigInt;
</del><ins>+    case HeapBigIntType:
+        return SpecHeapBigInt;
</ins><span class="cx">     case ArrayType:
</span><span class="cx">         return SpecArray;
</span><span class="cx">     case DerivedArrayType:
</span><span class="lines">@@ -632,6 +645,10 @@
</span><span class="cx"> 
</span><span class="cx">     if (type & SpecString)
</span><span class="cx">         type |= SpecString;
</span><ins>+
+    if (type & SpecBigInt)
+        type |= SpecBigInt;
+
</ins><span class="cx">     return type;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeSpeculatedTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/SpeculatedType.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/SpeculatedType.h    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecode/SpeculatedType.h       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -98,12 +98,14 @@
</span><span class="cx"> static constexpr SpeculatedType SpecOther                             = 1ull << 39; // It's definitely either Null or Undefined.
</span><span class="cx"> static constexpr SpeculatedType SpecMisc                              = SpecBoolean | SpecOther; // It's definitely either a boolean, Null, or Undefined.
</span><span class="cx"> static constexpr SpeculatedType SpecEmpty                             = 1ull << 40; // It's definitely an empty value marker.
</span><del>-static constexpr SpeculatedType SpecBigInt                            = 1ull << 41; // It's definitely a BigInt.
-static constexpr SpeculatedType SpecDataViewObject                    = 1ull << 42; // It's definitely a JSDataView.
</del><ins>+static constexpr SpeculatedType SpecHeapBigInt                        = 1ull << 41; // It's definitely a BigInt that is allocated on the heap
+static constexpr SpeculatedType SpecBigInt32                          = 1ull << 42; // It's definitely a small BigInt that is inline the JSValue
+static constexpr SpeculatedType SpecBigInt                            = SpecBigInt32 | SpecHeapBigInt;
+static constexpr SpeculatedType SpecDataViewObject                    = 1ull << 43; // It's definitely a JSDataView.
</ins><span class="cx"> static constexpr SpeculatedType SpecPrimitive                         = SpecString | SpecSymbol | SpecBytecodeNumber | SpecMisc | SpecBigInt; // It's any non-Object JSValue.
</span><span class="cx"> static constexpr SpeculatedType SpecObject                            = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecDateObject | SpecPromiseObject | SpecMapObject | SpecSetObject | SpecWeakMapObject | SpecWeakSetObject | SpecProxyObject | SpecDerivedArray | SpecObjectOther | SpecDataViewObject; // Bitmask used for testing for any kind of object prediction.
</span><del>-static constexpr SpeculatedType SpecCell                              = SpecObject | SpecString | SpecSymbol | SpecCellOther | SpecBigInt; // It's definitely a JSCell.
-static constexpr SpeculatedType SpecHeapTop                           = SpecCell | SpecBytecodeNumber | SpecMisc; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN.
</del><ins>+static constexpr SpeculatedType SpecCell                              = SpecObject | SpecString | SpecSymbol | SpecCellOther | SpecHeapBigInt; // It's definitely a JSCell.
+static constexpr SpeculatedType SpecHeapTop                           = SpecCell | SpecBigInt32 | SpecBytecodeNumber | SpecMisc; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN.
</ins><span class="cx"> static constexpr SpeculatedType SpecBytecodeTop                       = SpecHeapTop | SpecEmpty; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN. Corresponds to what could be found in a bytecode local.
</span><span class="cx"> static constexpr SpeculatedType SpecFullTop                           = SpecBytecodeTop | SpecFullNumber; // It can be anything that bytecode could see plus exotic encodings of numbers.
</span><span class="cx"> 
</span><span class="lines">@@ -195,9 +197,19 @@
</span><span class="cx">     return value == SpecSymbol;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool isBigInt32Speculation(SpeculatedType value)
+{
+    return value == SpecBigInt32;
+}
+
+inline bool isHeapBigIntSpeculation(SpeculatedType value)
+{
+    return value == SpecHeapBigInt;
+}
+
</ins><span class="cx"> inline bool isBigIntSpeculation(SpeculatedType value)
</span><span class="cx"> {
</span><del>-    return value == SpecBigInt;
</del><ins>+    return !!value && (value & SpecBigInt) == value;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool isArraySpeculation(SpeculatedType value)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1703,7 +1703,11 @@
</span><span class="cx">             }
</span><span class="cx">             if (Options::useBigInt() && value == "bigint") {
</span><span class="cx">                 rewind();
</span><del>-                OpIsCellWithType::emit(this, dst, op.m_value, BigIntType);
</del><ins>+#if USE(BIGINT32)
+                OpIsBigInt::emit(this, dst, op.m_value);
+#else
+                OpIsCellWithType::emit(this, dst, op.m_value, HeapBigIntType);
+#endif
</ins><span class="cx">                 return true;
</span><span class="cx">             }
</span><span class="cx">             if (value == "object") {
</span><span class="lines">@@ -2911,7 +2915,7 @@
</span><span class="cx">     return m_bigIntMap.ensure(BigIntMapEntry(identifier.impl(), radix, sign), [&] {
</span><span class="cx">         auto scope = DECLARE_CATCH_SCOPE(vm());
</span><span class="cx">         auto parseIntSign = sign ? JSBigInt::ParseIntSign::Signed : JSBigInt::ParseIntSign::Unsigned;
</span><del>-        JSBigInt* bigIntInMap = JSBigInt::parseInt(nullptr, vm(), identifier.string(), radix, JSBigInt::ErrorParseMode::ThrowExceptions, parseIntSign);
</del><ins>+        JSValue bigIntInMap = JSBigInt::parseInt(nullptr, vm(), identifier.string(), radix, JSBigInt::ErrorParseMode::ThrowExceptions, parseIntSign);
</ins><span class="cx">         scope.assertNoException();
</span><span class="cx">         addConstantValue(bigIntInMap);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1096,7 +1096,7 @@
</span><span class="cx"> 
</span><span class="cx">         using NumberMap = HashMap<double, JSValue>;
</span><span class="cx">         using IdentifierStringMap = HashMap<UniquedStringImpl*, JSString*, IdentifierRepHash>;
</span><del>-        using IdentifierBigIntMap = HashMap<BigIntMapEntry, JSBigInt*>;
</del><ins>+        using IdentifierBigIntMap = HashMap<BigIntMapEntry, JSValue>;
</ins><span class="cx">         using TemplateObjectDescriptorSet = HashSet<Ref<TemplateObjectDescriptor>>;
</span><span class="cx">         using TemplateDescriptorMap = HashMap<uint64_t, JSTemplateObjectDescriptor*, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>>;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -46,7 +46,6 @@
</span><span class="cx"> #include "JSPromiseConstructor.h"
</span><span class="cx"> #include "MathCommon.h"
</span><span class="cx"> #include "NumberConstructor.h"
</span><del>-#include "Operations.h"
</del><span class="cx"> #include "PutByIdStatus.h"
</span><span class="cx"> #include "StringObject.h"
</span><span class="cx"> #include "StructureCache.h"
</span><span class="lines">@@ -215,7 +214,7 @@
</span><span class="cx">         bool overridesToThis = false;
</span><span class="cx">         valueForNode.m_structure.forEach([&](RegisteredStructure structure) {
</span><span class="cx">             TypeInfo type = structure->typeInfo();
</span><del>-            ASSERT(type.isObject() || type.type() == StringType || type.type() == SymbolType || type.type() == BigIntType);
</del><ins>+            ASSERT(type.isObject() || type.type() == StringType || type.type() == SymbolType || type.type() == HeapBigIntType);
</ins><span class="cx">             if (!ecmaMode.isStrict())
</span><span class="cx">                 ASSERT(type.isObject());
</span><span class="cx">             // We don't need to worry about strings/symbols here since either:
</span><span class="lines">@@ -503,7 +502,15 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (node->child1().useKind() == BigIntUse)
</del><ins>+        if (node->child1().useKind() == BigInt32Use) {
+#if USE(BIGINT32)
+            setTypeForNode(node, SpecBigInt32);
+#else
+            RELEASE_ASSERT_NOT_REACHED();
+#endif
+        } else if (node->child1().useKind() == HeapBigIntUse)
+            setTypeForNode(node, SpecHeapBigInt);
+        else if (node->child1().useKind() == AnyBigIntUse)
</ins><span class="cx">             setTypeForNode(node, SpecBigInt);
</span><span class="cx">         else {
</span><span class="cx">             clobberWorld();
</span><span class="lines">@@ -533,7 +540,16 @@
</span><span class="cx">         if (handleConstantBinaryBitwiseOp(node))
</span><span class="cx">             break;
</span><span class="cx"> 
</span><del>-        if (node->binaryUseKind() == BigIntUse)
</del><ins>+        // FIXME: this use of binaryUseKind means that we cannot specialize to (for example) a HeapBigInt left-operand and a BigInt32 right-operand.
+        if (node->binaryUseKind() == BigInt32Use) {
+#if USE(BIGINT32)
+            setTypeForNode(node, SpecBigInt32);
+#else
+            RELEASE_ASSERT_NOT_REACHED();
+#endif
+        } else if (node->binaryUseKind() == HeapBigIntUse)
+            setTypeForNode(node, SpecHeapBigInt);
+        else if (node->binaryUseKind() == AnyBigIntUse)
</ins><span class="cx">             setTypeForNode(node, SpecBigInt);
</span><span class="cx">         else {
</span><span class="cx">             clobberWorld();
</span><span class="lines">@@ -723,11 +739,14 @@
</span><span class="cx"> 
</span><span class="cx">     case ValueSub:
</span><span class="cx">     case ValueAdd: {
</span><del>-        DFG_ASSERT(m_graph, node, node->binaryUseKind() == UntypedUse || node->binaryUseKind() == BigIntUse);
-        if (node->binaryUseKind() == BigIntUse)
</del><ins>+        if (node->binaryUseKind() == HeapBigIntUse)
+            setTypeForNode(node, SpecHeapBigInt);
+        else if (node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use)
</ins><span class="cx">             setTypeForNode(node, SpecBigInt);
</span><span class="cx">         else {
</span><ins>+            DFG_ASSERT(m_graph, node, node->binaryUseKind() == UntypedUse);
</ins><span class="cx">             clobberWorld();
</span><ins>+            // FIXME: do we really need SpecString here for ValueSub? It seems like we only need it for ValueAdd.
</ins><span class="cx">             setTypeForNode(node, SpecString | SpecBytecodeNumber | SpecBigInt);
</span><span class="cx">         }
</span><span class="cx">         break;
</span><span class="lines">@@ -887,6 +906,7 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case ValueNegate: {
</span><ins>+        // FIXME: we could do much smarter things for BigInts, see ValueAdd/ValueSub.
</ins><span class="cx">         clobberWorld();
</span><span class="cx">         setTypeForNode(node, SpecBytecodeNumber | SpecBigInt);
</span><span class="cx">         break;
</span><span class="lines">@@ -959,7 +979,11 @@
</span><span class="cx">         case DoubleRepUse:
</span><span class="cx">             setNonCellTypeForNode(node, typeOfDoubleIncOrDec(forNode(node->child1()).m_type));
</span><span class="cx">             break;
</span><del>-        case BigIntUse:
</del><ins>+        case HeapBigIntUse:
+            setTypeForNode(node, SpecHeapBigInt);
+            break;
+        case AnyBigIntUse:
+        case BigInt32Use:
</ins><span class="cx">             setTypeForNode(node, SpecBigInt);
</span><span class="cx">             break;
</span><span class="cx">         default:
</span><span class="lines">@@ -975,7 +999,7 @@
</span><span class="cx">         JSValue childY = forNode(node->child2()).value();
</span><span class="cx">         if (childX && childY && childX.isNumber() && childY.isNumber()) {
</span><span class="cx">             // We need to call `didFoldClobberWorld` here because this path is only possible
</span><del>-            // when node->useKind is UntypedUse. In the case of BigIntUse, children will be
</del><ins>+            // when node->useKind is UntypedUse. In the case of AnyBigIntUse or friends, children will be
</ins><span class="cx">             // cleared by `AbstractInterpreter::executeEffects`.
</span><span class="cx">             didFoldClobberWorld();
</span><span class="cx">             // Our boxing scheme here matches what we do in operationValuePow.
</span><span class="lines">@@ -983,7 +1007,9 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (node->binaryUseKind() == BigIntUse)
</del><ins>+        if (node->binaryUseKind() == HeapBigIntUse)
+            setTypeForNode(node, SpecHeapBigInt);
+        else if (node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use)
</ins><span class="cx">             setTypeForNode(node, SpecBigInt);
</span><span class="cx">         else {
</span><span class="cx">             clobberWorld();
</span><span class="lines">@@ -993,7 +1019,10 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     case ValueMul: {
</span><del>-        if (node->binaryUseKind() == BigIntUse)
</del><ins>+        // FIXME: why is this code not shared with ValueSub?
+        if (node->binaryUseKind() == HeapBigIntUse)
+            setTypeForNode(node, SpecHeapBigInt);
+        else if (node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use)
</ins><span class="cx">             setTypeForNode(node, SpecBigInt);
</span><span class="cx">         else {
</span><span class="cx">             clobberWorld();
</span><span class="lines">@@ -1057,7 +1086,9 @@
</span><span class="cx">         if (handleConstantDivOp(node))
</span><span class="cx">             break;
</span><span class="cx"> 
</span><del>-        if (node->binaryUseKind() == BigIntUse)
</del><ins>+        if (node->binaryUseKind() == HeapBigIntUse)
+            setTypeForNode(node, SpecHeapBigInt);
+        else if (node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use)
</ins><span class="cx">             setTypeForNode(node, SpecBigInt);
</span><span class="cx">         else {
</span><span class="cx">             clobberWorld();
</span><span class="lines">@@ -1381,6 +1412,7 @@
</span><span class="cx">     case IsUndefinedOrNull:
</span><span class="cx">     case IsBoolean:
</span><span class="cx">     case IsNumber:
</span><ins>+    case IsBigInt:
</ins><span class="cx">     case NumberIsInteger:
</span><span class="cx">     case IsObject:
</span><span class="cx">     case IsObjectOrNull:
</span><span class="lines">@@ -1409,6 +1441,9 @@
</span><span class="cx">             case IsNumber:
</span><span class="cx">                 setConstant(node, jsBoolean(child.value().isNumber()));
</span><span class="cx">                 break;
</span><ins>+            case IsBigInt:
+                setConstant(node, jsBoolean(child.value().isBigInt()));
+                break;
</ins><span class="cx">             case NumberIsInteger:
</span><span class="cx">                 setConstant(node, jsBoolean(NumberConstructor::isIntegerImpl(child.value())));
</span><span class="cx">                 break;
</span><span class="lines">@@ -1563,7 +1598,22 @@
</span><span class="cx">             }
</span><span class="cx">             
</span><span class="cx">             break;
</span><ins>+        case IsBigInt:
+            if (!(child.m_type & ~SpecBigInt)) {
+                setConstant(node, jsBoolean(true));
+                constantWasSet = true;
+                break;
+            }
</ins><span class="cx"> 
</span><ins>+            if (!(child.m_type & SpecBigInt)) {
+                setConstant(node, jsBoolean(false));
+                constantWasSet = true;
+                break;
+            }
+
+            // FIXME: if the SpeculatedType informs us that we won't have a BigInt32 (or that we won't have a HeapBigInt), then we can transform this node into a IsCellWithType(HeapBigIntType) (or a hypothetical IsBigInt32 node).
+
+            break;
</ins><span class="cx">         case NumberIsInteger:
</span><span class="cx">             if (!(child.m_type & ~SpecInt32Only)) {
</span><span class="cx">                 setConstant(node, jsBoolean(true));
</span><span class="lines">@@ -1937,13 +1987,14 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        // FIXME: why is this check here, and not later (after the type-based replacement by false).
+        // Saam seems to agree that the two checks could be switched, I'll try that in a separate patch
</ins><span class="cx">         if (node->isBinaryUseKind(UntypedUse)) {
</span><del>-            // FIXME: Revisit this condition when introducing BigInt to JSC.
-            auto isNonStringCellConstant = [] (JSValue value) {
-                return value && value.isCell() && !value.isString();
</del><ins>+            auto isNonStringAndNonBigIntCellConstant = [] (JSValue value) {
+                return value && value.isCell() && !value.isString() && !value.isHeapBigInt();
</ins><span class="cx">             };
</span><span class="cx"> 
</span><del>-            if (isNonStringCellConstant(left) || isNonStringCellConstant(right)) {
</del><ins>+            if (isNonStringAndNonBigIntCellConstant(left) || isNonStringAndNonBigIntCellConstant(right)) {
</ins><span class="cx">                 m_state.setShouldTryConstantFolding(true);
</span><span class="cx">                 setNonCellTypeForNode(node, SpecBoolean);
</span><span class="cx">                 break;
</span><span class="lines">@@ -1958,19 +2009,24 @@
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         if (node->child1() == node->child2()) {
</span><del>-            if (node->isBinaryUseKind(BooleanUse) ||
-                node->isBinaryUseKind(Int32Use) ||
-                node->isBinaryUseKind(Int52RepUse) ||
-                node->isBinaryUseKind(StringUse) ||
-                node->isBinaryUseKind(StringIdentUse) ||
-                node->isBinaryUseKind(SymbolUse) ||
-                node->isBinaryUseKind(ObjectUse) ||
-                node->isBinaryUseKind(MiscUse, UntypedUse) ||
-                node->isBinaryUseKind(UntypedUse, MiscUse) ||
-                node->isBinaryUseKind(StringIdentUse, NotStringVarUse) ||
-                node->isBinaryUseKind(NotStringVarUse, StringIdentUse) ||
-                node->isBinaryUseKind(StringUse, UntypedUse) ||
-                node->isBinaryUseKind(UntypedUse, StringUse)) {
</del><ins>+            // FIXME: Is there any case not involving NaN where x === x is not guaranteed to return true?
+            // If not I might slightly simplify that check.
+            if (node->isBinaryUseKind(BooleanUse)
+                || node->isBinaryUseKind(Int32Use)
+                || node->isBinaryUseKind(Int52RepUse)
+                || node->isBinaryUseKind(StringUse)
+                || node->isBinaryUseKind(StringIdentUse)
+                || node->isBinaryUseKind(SymbolUse)
+                || node->isBinaryUseKind(ObjectUse)
+                || node->isBinaryUseKind(MiscUse, UntypedUse)
+                || node->isBinaryUseKind(UntypedUse, MiscUse)
+                || node->isBinaryUseKind(StringIdentUse, NotStringVarUse)
+                || node->isBinaryUseKind(NotStringVarUse, StringIdentUse)
+                || node->isBinaryUseKind(StringUse, UntypedUse)
+                || node->isBinaryUseKind(UntypedUse, StringUse)
+                || node->isBinaryUseKind(BigInt32Use)
+                || node->isBinaryUseKind(HeapBigIntUse)
+                || node->isBinaryUseKind(AnyBigIntUse)) {
</ins><span class="cx">                 setConstant(node, jsBoolean(true));
</span><span class="cx">                 break;
</span><span class="cx">             }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -5722,6 +5722,17 @@
</span><span class="cx">             NEXT_OPCODE(op_is_number);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        case op_is_big_int: {
+#if USE(BIGINT32)
+            auto bytecode = currentInstruction->as<OpIsBigInt>();
+            Node* value = get(bytecode.m_operand);
+            set(bytecode.m_dst, addToGraph(IsBigInt, value));
+            NEXT_OPCODE(op_is_big_int);
+#else
+            RELEASE_ASSERT_NOT_REACHED();
+#endif
+        }
+
</ins><span class="cx">         case op_is_cell_with_type: {
</span><span class="cx">             auto bytecode = currentInstruction->as<OpIsCellWithType>();
</span><span class="cx">             Node* value = get(bytecode.m_operand);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -149,6 +149,7 @@
</span><span class="cx">     case op_is_undefined_or_null:
</span><span class="cx">     case op_is_boolean:
</span><span class="cx">     case op_is_number:
</span><ins>+    case op_is_big_int:
</ins><span class="cx">     case op_is_object:
</span><span class="cx">     case op_is_object_or_null:
</span><span class="cx">     case op_is_cell_with_type:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -175,6 +175,7 @@
</span><span class="cx">     case IsUndefinedOrNull:
</span><span class="cx">     case IsBoolean:
</span><span class="cx">     case IsNumber:
</span><ins>+    case IsBigInt:
</ins><span class="cx">     case NumberIsInteger:
</span><span class="cx">     case IsObject:
</span><span class="cx">     case IsTypedArrayView:
</span><span class="lines">@@ -260,7 +261,7 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     case ValueBitNot:
</span><del>-        if (node->child1().useKind() == BigIntUse) {
</del><ins>+        if (node->child1().useKind() == AnyBigIntUse || node->child1().useKind() == BigInt32Use || node->child1().useKind() == HeapBigIntUse) {
</ins><span class="cx">             def(PureValue(node));
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -680,7 +681,9 @@
</span><span class="cx">         case Int32Use:
</span><span class="cx">         case Int52RepUse:
</span><span class="cx">         case DoubleRepUse:
</span><del>-        case BigIntUse:
</del><ins>+        case BigInt32Use:
+        case HeapBigIntUse:
+        case AnyBigIntUse:
</ins><span class="cx">             def(PureValue(node));
</span><span class="cx">             return;
</span><span class="cx">         case UntypedUse:
</span><span class="lines">@@ -702,7 +705,8 @@
</span><span class="cx">     case ValuePow:
</span><span class="cx">     case ValueBitLShift:
</span><span class="cx">     case ValueBitRShift:
</span><del>-        if (node->isBinaryUseKind(BigIntUse)) {
</del><ins>+        // FIXME: this use of single-argument isBinaryUseKind would prevent us from specializing (for example) for a HeapBigInt left-operand and a BigInt32 right-operand.
+        if (node->isBinaryUseKind(AnyBigIntUse) || node->isBinaryUseKind(BigInt32Use) || node->isBinaryUseKind(HeapBigIntUse)) {
</ins><span class="cx">             def(PureValue(node));
</span><span class="cx">             return;
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -147,15 +147,14 @@
</span><span class="cx">                     JSValue child1Constant = m_state.forNode(node->child1().node()).value();
</span><span class="cx">                     JSValue child2Constant = m_state.forNode(node->child2().node()).value();
</span><span class="cx"> 
</span><del>-                    // FIXME: Revisit this condition when introducing BigInt to JSC.
-                    auto isNonStringOrBigIntCellConstant = [] (JSValue value) {
-                        return value && value.isCell() && !value.isString() && !value.isBigInt();
</del><ins>+                    auto isNonStringAndNonBigIntCellConstant = [] (JSValue value) {
+                        return value && value.isCell() && !value.isString() && !value.isHeapBigInt();
</ins><span class="cx">                     };
</span><span class="cx"> 
</span><del>-                    if (isNonStringOrBigIntCellConstant(child1Constant)) {
</del><ins>+                    if (isNonStringAndNonBigIntCellConstant(child1Constant)) {
</ins><span class="cx">                         node->convertToCompareEqPtr(m_graph.freezeStrong(child1Constant.asCell()), node->child2());
</span><span class="cx">                         changed = true;
</span><del>-                    } else if (isNonStringOrBigIntCellConstant(child2Constant)) {
</del><ins>+                    } else if (isNonStringAndNonBigIntCellConstant(child2Constant)) {
</ins><span class="cx">                         node->convertToCompareEqPtr(m_graph.freezeStrong(child2Constant.asCell()), node->child1());
</span><span class="cx">                         changed = true;
</span><span class="cx">                     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -31,7 +31,6 @@
</span><span class="cx"> #include "DFGClobberize.h"
</span><span class="cx"> #include "DFGGraph.h"
</span><span class="cx"> #include "DFGNode.h"
</span><del>-#include "Operations.h"
</del><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><span class="lines">@@ -147,6 +146,7 @@
</span><span class="cx">     case IsUndefinedOrNull:
</span><span class="cx">     case IsBoolean:
</span><span class="cx">     case IsNumber:
</span><ins>+    case IsBigInt:
</ins><span class="cx">     case NumberIsInteger:
</span><span class="cx">     case IsObject:
</span><span class="cx">     case IsObjectOrNull:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -202,14 +202,34 @@
</span><span class="cx">                 fixEdge<Int32Use>(node->child1());
</span><span class="cx">                 fixEdge<Int32Use>(node->child2());
</span><span class="cx">                 node->setResult(NodeResultInt32);
</span><ins>+            } else if (node->child1()->shouldSpeculateHeapBigInt()) {
+                // FIXME: the freezing does not appear useful (since the JSCell is kept alive by vm), but it refuses to compile otherwise.
+                // FIXME: we might optimize inc/dec to a specialized function call instead in that case.
+                node->setOp(op == Inc ? ValueAdd : ValueSub);
+                nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecHeapBigInt, JSConstant, node->origin, OpInfo(m_graph.freeze(vm().heapBigIntConstantOne.get())));
+                node->children.setChild2(Edge(nodeConstantOne));
+                fixEdge<HeapBigIntUse>(node->child1());
+                fixEdge<HeapBigIntUse>(node->child2());
+                // HeapBigInts are cells, so the default of NodeResultJS is good here
+#if USE(BIGINT32)
+            } else if (node->child1()->shouldSpeculateBigInt32()) {
+                node->setOp(op == Inc ? ValueAdd : ValueSub);
+                nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecBigInt32, JSConstant, node->origin, OpInfo(m_graph.freeze(JSValue(JSValue::JSBigInt32, 1))));
+                node->children.setChild2(Edge(nodeConstantOne));
+                fixEdge<BigInt32Use>(node->child1());
+                fixEdge<BigInt32Use>(node->child2());
+                // The default of NodeResultJS is good enough for now.
+                // FIXME: consider having a special representation for small BigInts instead.
</ins><span class="cx">             } else if (node->child1()->shouldSpeculateBigInt()) {
</span><span class="cx">                 // FIXME: the freezing does not appear useful (since the JSCell is kept alive by vm), but it refuses to compile otherwise.
</span><ins>+                // FIXME: we might optimize inc/dec to a specialized function call instead in that case.
</ins><span class="cx">                 node->setOp(op == Inc ? ValueAdd : ValueSub);
</span><del>-                nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecBigInt, JSConstant, node->origin, OpInfo(m_graph.freeze(vm().bigIntConstantOne.get())));
</del><ins>+                nodeConstantOne = m_insertionSet.insertNode(m_indexInBlock, SpecBigInt32, JSConstant, node->origin, OpInfo(m_graph.freeze(JSValue(JSValue::JSBigInt32, 1))));
</ins><span class="cx">                 node->children.setChild2(Edge(nodeConstantOne));
</span><del>-                fixEdge<BigIntUse>(node->child1());
-                fixEdge<BigIntUse>(node->child2());
-                // BigInts are currently cells, so the default of NodeResultJS is good here
</del><ins>+                fixEdge<AnyBigIntUse>(node->child1());
+                fixEdge<AnyBigIntUse>(node->child2());
+                // The default of NodeResultJS is good here
+#endif // USE(BIGINT32)
</ins><span class="cx">             } else if (node->child1()->shouldSpeculateInt52()) {
</span><span class="cx">                 node->setOp(op == Inc ? ArithAdd : ArithSub);
</span><span class="cx">                 node->setArithMode(Arith::CheckOverflow);
</span><span class="lines">@@ -235,12 +255,20 @@
</span><span class="cx">             Edge& child1 = node->child1();
</span><span class="cx">             Edge& child2 = node->child2();
</span><span class="cx"> 
</span><ins>+            if (Node::shouldSpeculateHeapBigInt(child1.node(), child2.node())) {
+                fixEdge<HeapBigIntUse>(child1);
+                fixEdge<HeapBigIntUse>(child2);
+                break;
+            }
+
+#if USE(BIGINT32)
</ins><span class="cx">             if (Node::shouldSpeculateBigInt(child1.node(), child2.node())) {
</span><del>-                fixEdge<BigIntUse>(child1);
-                fixEdge<BigIntUse>(child2);
</del><ins>+                fixEdge<AnyBigIntUse>(child1);
+                fixEdge<AnyBigIntUse>(child2);
</ins><span class="cx">                 break; 
</span><span class="cx">             }
</span><del>-            
</del><ins>+#endif
+
</ins><span class="cx">             if (Node::shouldSpeculateUntypedForArithmetic(node->child1().node(), node->child2().node())) {
</span><span class="cx">                 fixEdge<UntypedUse>(child1);
</span><span class="cx">                 fixEdge<UntypedUse>(child2);
</span><span class="lines">@@ -268,8 +296,21 @@
</span><span class="cx">         case ValueBitOr:
</span><span class="cx">         case ValueBitAnd: {
</span><span class="cx">             if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) {
</span><del>-                fixEdge<BigIntUse>(node->child1());
-                fixEdge<BigIntUse>(node->child2());
</del><ins>+#if USE(BIGINT32)
+                if (Node::shouldSpeculateBigInt32(node->child1().node(), node->child2().node())) {
+                    fixEdge<BigInt32Use>(node->child1());
+                    fixEdge<BigInt32Use>(node->child2());
+                } else if (Node::shouldSpeculateHeapBigInt(node->child1().node(), node->child2().node())) {
+                    fixEdge<HeapBigIntUse>(node->child1());
+                    fixEdge<HeapBigIntUse>(node->child2());
+                } else {
+                    fixEdge<AnyBigIntUse>(node->child1());
+                    fixEdge<AnyBigIntUse>(node->child2());
+                }
+#else
+                fixEdge<HeapBigIntUse>(node->child1());
+                fixEdge<HeapBigIntUse>(node->child2());
+#endif
</ins><span class="cx">                 node->clearFlags(NodeMustGenerate);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="lines">@@ -313,7 +354,17 @@
</span><span class="cx"> 
</span><span class="cx">             if (operandEdge.node()->shouldSpeculateBigInt()) {
</span><span class="cx">                 node->clearFlags(NodeMustGenerate);
</span><del>-                fixEdge<BigIntUse>(operandEdge);
</del><ins>+
+#if USE(BIGINT32)
+                if (operandEdge.node()->shouldSpeculateBigInt32())
+                    fixEdge<BigInt32Use>(operandEdge);
+                else if (operandEdge.node()->shouldSpeculateHeapBigInt())
+                    fixEdge<HeapBigIntUse>(operandEdge);
+                else
+                    fixEdge<AnyBigIntUse>(operandEdge);
+#else
+                fixEdge<HeapBigIntUse>(operandEdge);
+#endif
</ins><span class="cx">             } else if (operandEdge.node()->shouldSpeculateUntypedForBitOps())
</span><span class="cx">                 fixEdge<UntypedUse>(operandEdge);
</span><span class="cx">             else {
</span><span class="lines">@@ -458,9 +509,17 @@
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            if (Node::shouldSpeculateBigInt(child1.node(), child2.node())) {
-                fixEdge<BigIntUse>(child1);
-                fixEdge<BigIntUse>(child2);
</del><ins>+            if (Node::shouldSpeculateHeapBigInt(child1.node(), child2.node())) {
+                fixEdge<HeapBigIntUse>(child1);
+                fixEdge<HeapBigIntUse>(child2);
+#if USE(BIGINT32)
+            } else if (Node::shouldSpeculateBigInt32(child1.node(), child2.node())) {
+                fixEdge<BigInt32Use>(child1);
+                fixEdge<BigInt32Use>(child2);
+            } else if (Node::shouldSpeculateBigInt(child1.node(), child2.node())) {
+                fixEdge<AnyBigIntUse>(child1);
+                fixEdge<AnyBigIntUse>(child2);
+#endif
</ins><span class="cx">             } else {
</span><span class="cx">                 fixEdge<UntypedUse>(child1);
</span><span class="cx">                 fixEdge<UntypedUse>(child2);
</span><span class="lines">@@ -546,8 +605,21 @@
</span><span class="cx">             Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><span class="cx">             if (Node::shouldSpeculateBigInt(leftChild.node(), rightChild.node())) {
</span><del>-                fixEdge<BigIntUse>(node->child1());
-                fixEdge<BigIntUse>(node->child2());
</del><ins>+#if USE(BIGINT32)
+                if (Node::shouldSpeculateBigInt32(leftChild.node(), rightChild.node())) {
+                    fixEdge<BigInt32Use>(node->child1());
+                    fixEdge<BigInt32Use>(node->child2());
+                } else if (Node::shouldSpeculateHeapBigInt(leftChild.node(), rightChild.node())) {
+                    fixEdge<HeapBigIntUse>(node->child1());
+                    fixEdge<HeapBigIntUse>(node->child2());
+                } else {
+                    fixEdge<AnyBigIntUse>(node->child1());
+                    fixEdge<AnyBigIntUse>(node->child2());
+                }
+#else
+                fixEdge<HeapBigIntUse>(node->child1());
+                fixEdge<HeapBigIntUse>(node->child2());
+#endif
</ins><span class="cx">                 node->clearFlags(NodeMustGenerate);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="lines">@@ -588,12 +660,20 @@
</span><span class="cx">             Edge& leftChild = node->child1();
</span><span class="cx">             Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><ins>+            if (Node::shouldSpeculateHeapBigInt(leftChild.node(), rightChild.node())) {
+                fixEdge<HeapBigIntUse>(leftChild);
+                fixEdge<HeapBigIntUse>(rightChild);
+                node->clearFlags(NodeMustGenerate);
+                break;
+            }
+#if USE(BIGINT32)
</ins><span class="cx">             if (Node::shouldSpeculateBigInt(leftChild.node(), rightChild.node())) {
</span><del>-                fixEdge<BigIntUse>(leftChild);
-                fixEdge<BigIntUse>(rightChild);
</del><ins>+                fixEdge<AnyBigIntUse>(leftChild);
+                fixEdge<AnyBigIntUse>(rightChild);
</ins><span class="cx">                 node->clearFlags(NodeMustGenerate);
</span><span class="cx">                 break; 
</span><span class="cx">             }
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx">             if (Node::shouldSpeculateUntypedForArithmetic(leftChild.node(), rightChild.node())) {
</span><span class="cx">                 fixEdge<UntypedUse>(leftChild);
</span><span class="lines">@@ -657,12 +737,20 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case ValuePow: {
</span><ins>+            if (Node::shouldSpeculateHeapBigInt(node->child1().node(), node->child1().node())) {
+                fixEdge<HeapBigIntUse>(node->child1());
+                fixEdge<HeapBigIntUse>(node->child2());
+                node->clearFlags(NodeMustGenerate);
+                break;
+            }
+#if USE(BIGINT32)
</ins><span class="cx">             if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) {
</span><del>-                fixEdge<BigIntUse>(node->child1());
-                fixEdge<BigIntUse>(node->child2());
</del><ins>+                fixEdge<AnyBigIntUse>(node->child1());
+                fixEdge<AnyBigIntUse>(node->child2());
</ins><span class="cx">                 node->clearFlags(NodeMustGenerate);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx">             if (Node::shouldSpeculateUntypedForArithmetic(node->child1().node(), node->child2().node())) {
</span><span class="cx">                 fixEdge<UntypedUse>(node->child1());
</span><span class="lines">@@ -2548,6 +2636,7 @@
</span><span class="cx">         case IsUndefinedOrNull:
</span><span class="cx">         case IsBoolean:
</span><span class="cx">         case IsNumber:
</span><ins>+        case IsBigInt:
</ins><span class="cx">         case IsObjectOrNull:
</span><span class="cx">         case IsFunction:
</span><span class="cx">         case CreateDirectArguments:
</span><span class="lines">@@ -2889,7 +2978,16 @@
</span><span class="cx">             }
</span><span class="cx">             
</span><span class="cx">             if (node->child1()->shouldSpeculateBigInt()) {
</span><del>-                fixEdge<BigIntUse>(node->child1());
</del><ins>+#if USE(BIGINT32)
+                if (node->child1()->shouldSpeculateBigInt32())
+                    fixEdge<BigInt32Use>(node->child1());
+                else if (node->child1()->shouldSpeculateHeapBigInt())
+                    fixEdge<HeapBigIntUse>(node->child1());
+                else
+                    fixEdge<AnyBigIntUse>(node->child1());
+#else
+                fixEdge<HeapBigIntUse>(node->child1());
+#endif
</ins><span class="cx">                 node->convertToIdentity();
</span><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="lines">@@ -2962,7 +3060,16 @@
</span><span class="cx">     {
</span><span class="cx">         // If the prediction of the child is BigInt, we attempt to convert ToNumeric to Identity, since it can only return a BigInt when fed a BigInt.
</span><span class="cx">         if (node->child1()->shouldSpeculateBigInt()) {
</span><del>-            fixEdge<BigIntUse>(node->child1());
</del><ins>+#if USE(BIGINT32)
+            if (node->child1()->shouldSpeculateBigInt32())
+                fixEdge<BigInt32Use>(node->child1());
+            else if (node->child1()->shouldSpeculateHeapBigInt())
+                fixEdge<HeapBigIntUse>(node->child1());
+            else
+                fixEdge<AnyBigIntUse>(node->child1());
+#else
+            fixEdge<HeapBigIntUse>(node->child1());
+#endif
</ins><span class="cx">             node->convertToIdentity();
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -3456,7 +3563,7 @@
</span><span class="cx">         case StringUse:
</span><span class="cx">         case KnownStringUse:
</span><span class="cx">         case SymbolUse:
</span><del>-        case BigIntUse:
</del><ins>+        case HeapBigIntUse:
</ins><span class="cx">         case StringObjectUse:
</span><span class="cx">         case StringOrStringObjectUse:
</span><span class="cx">             if (alwaysUnboxSimplePrimitives()
</span><span class="lines">@@ -3463,6 +3570,8 @@
</span><span class="cx">                 || isCellSpeculation(variable->prediction()))
</span><span class="cx">                 m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
</span><span class="cx">             break;
</span><ins>+        // FIXME: what should we do about BigInt32Use and AnyBigIntUse ?
+        // Also more broadly, what about all of the UseKinds which are not listed in that switch?
</ins><span class="cx">         default:
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="lines">@@ -3976,12 +4085,26 @@
</span><span class="cx">             node->setOpAndDefaultFlags(CompareStrictEq);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        if (Node::shouldSpeculateHeapBigInt(node->child1().node(), node->child2().node())) {
+            fixEdge<HeapBigIntUse>(node->child1());
+            fixEdge<HeapBigIntUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+#if USE(BIGINT32)
+        if (Node::shouldSpeculateBigInt32(node->child1().node(), node->child2().node())) {
+            fixEdge<BigInt32Use>(node->child1());
+            fixEdge<BigInt32Use>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
</ins><span class="cx">         if (Node::shouldSpeculateBigInt(node->child1().node(), node->child2().node())) {
</span><del>-            fixEdge<BigIntUse>(node->child1());
-            fixEdge<BigIntUse>(node->child2());
</del><ins>+            fixEdge<AnyBigIntUse>(node->child1());
+            fixEdge<AnyBigIntUse>(node->child2());
</ins><span class="cx">             node->setOpAndDefaultFlags(CompareStrictEq);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+#endif
</ins><span class="cx">         if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
</span><span class="cx">             fixEdge<StringIdentUse>(node->child1());
</span><span class="cx">             fixEdge<StringIdentUse>(node->child2());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1540,7 +1540,7 @@
</span><span class="cx">         return freeze(jsNumber(0));
</span><span class="cx"> 
</span><span class="cx">     if (speculationContains(prediction, SpecBigInt))
</span><del>-        return freeze(m_vm.bigIntConstantOne.get());
</del><ins>+        return freeze(m_vm.heapBigIntConstantOne.get());
</ins><span class="cx"> 
</span><span class="cx">     if (speculationContains(prediction, SpecString | SpecSymbol))
</span><span class="cx">         return freeze(m_vm.smallStrings.emptyString());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMayExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -32,7 +32,6 @@
</span><span class="cx"> #include "DFGGraph.h"
</span><span class="cx"> #include "DFGNode.h"
</span><span class="cx"> #include "DFGNullAbstractState.h"
</span><del>-#include "Operations.h"
</del><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2018 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -2622,6 +2622,18 @@
</span><span class="cx">     {
</span><span class="cx">         return isSymbolSpeculation(prediction());
</span><span class="cx">     }
</span><ins>+
+#if USE(BIGINT32)
+    bool shouldSpeculateBigInt32()
+    {
+        return isBigInt32Speculation(prediction());
+    }
+#endif
+
+    bool shouldSpeculateHeapBigInt()
+    {
+        return isHeapBigIntSpeculation(prediction());
+    }
</ins><span class="cx">     
</span><span class="cx">     bool shouldSpeculateBigInt()
</span><span class="cx">     {
</span><span class="lines">@@ -2822,7 +2834,19 @@
</span><span class="cx">     {
</span><span class="cx">         return op1->shouldSpeculateBigInt() && op2->shouldSpeculateBigInt();
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+#if USE(BIGINT32)
+    static bool shouldSpeculateBigInt32(Node* op1, Node* op2)
+    {
+        return op1->shouldSpeculateBigInt32() && op2->shouldSpeculateBigInt32();
+    }
+#endif
+
+    static bool shouldSpeculateHeapBigInt(Node* op1, Node* op2)
+    {
+        return op1->shouldSpeculateHeapBigInt() && op2->shouldSpeculateHeapBigInt();
+    }
+
</ins><span class="cx">     static bool shouldSpeculateFinalObject(Node* op1, Node* op2)
</span><span class="cx">     {
</span><span class="cx">         return op1->shouldSpeculateFinalObject() && op2->shouldSpeculateFinalObject();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeFlagsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -54,6 +54,7 @@
</span><span class="cx"> #define NodeMayNegZeroInBaseline         0x00200
</span><span class="cx"> #define NodeMayNegZeroInDFG              0x00400
</span><span class="cx"> #define NodeMayHaveNonNumericResult      0x00800
</span><ins>+// FIXME: we should have separate flags for HeapBigInt and BigInt32, currently prediction propagation will pessimize things.
</ins><span class="cx"> #define NodeMayHaveBigIntResult          0x01000
</span><span class="cx"> #define NodeMayHaveNonIntResult          (NodeMayHaveDoubleResult | NodeMayHaveNonNumericResult | NodeMayHaveBigIntResult)
</span><span class="cx">                                 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -395,6 +395,8 @@
</span><span class="cx">     macro(IsUndefinedOrNull, NodeResultBoolean) \
</span><span class="cx">     macro(IsBoolean, NodeResultBoolean) \
</span><span class="cx">     macro(IsNumber, NodeResultBoolean) \
</span><ins>+    /* IsBigInt is only used when USE_BIGINT32. Otherwise we emit IsCellWithType */\
+    macro(IsBigInt, NodeResultBoolean) \
</ins><span class="cx">     macro(NumberIsInteger, NodeResultBoolean) \
</span><span class="cx">     macro(IsObject, NodeResultBoolean) \
</span><span class="cx">     macro(IsObjectOrNull, NodeResultBoolean) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRExit.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -383,10 +383,13 @@
</span><span class="cx">                 // We can't be sure that we have a spare register. So use the numberTagRegister,
</span><span class="cx">                 // since we know how to restore it.
</span><span class="cx">                 jit.load64(AssemblyHelpers::Address(exit.m_jsValueSource.asAddress()), GPRInfo::numberTagRegister);
</span><del>-                profile.emitReportValue(jit, JSValueRegs(GPRInfo::numberTagRegister));
</del><ins>+                // We also use the notCellMaskRegister as the scratch register, for the same reason.
+                // FIXME: find a less gross way of doing this, maybe through delaying these operations until we actually have some spare registers around?
+                profile.emitReportValue(jit, JSValueRegs(GPRInfo::numberTagRegister), GPRInfo::notCellMaskRegister, DoNotHaveTagRegisters);
</ins><span class="cx">                 jit.move(AssemblyHelpers::TrustedImm64(JSValue::NumberTag), GPRInfo::numberTagRegister);
</span><span class="cx">             } else
</span><del>-                profile.emitReportValue(jit, JSValueRegs(exit.m_jsValueSource.gpr()));
</del><ins>+                profile.emitReportValue(jit, JSValueRegs(exit.m_jsValueSource.gpr()), GPRInfo::notCellMaskRegister, DoNotHaveTagRegisters);
+            jit.move(AssemblyHelpers::TrustedImm64(JSValue::NotCellMask), GPRInfo::notCellMaskRegister);
</ins><span class="cx"> #else // not USE(JSVALUE64)
</span><span class="cx">             if (exit.m_jsValueSource.isAddress()) {
</span><span class="cx">                 // Save a register so we can use it.
</span><span class="lines">@@ -398,7 +401,7 @@
</span><span class="cx">                 JSValueRegs scratch(scratchTag, scratchPayload);
</span><span class="cx">                 
</span><span class="cx">                 jit.loadValue(exit.m_jsValueSource.asAddress(), scratch);
</span><del>-                profile.emitReportValue(jit, scratch);
</del><ins>+                profile.emitReportValue(jit, scratch, InvalidGPRReg);
</ins><span class="cx">                 
</span><span class="cx">                 jit.popToRestore(scratchTag);
</span><span class="cx">                 jit.popToRestore(scratchPayload);
</span><span class="lines">@@ -407,10 +410,10 @@
</span><span class="cx">                 jit.pushToSave(scratchTag);
</span><span class="cx">                 jit.move(AssemblyHelpers::TrustedImm32(exit.m_jsValueSource.tag()), scratchTag);
</span><span class="cx">                 JSValueRegs value(scratchTag, exit.m_jsValueSource.payloadGPR());
</span><del>-                profile.emitReportValue(jit, value);
</del><ins>+                profile.emitReportValue(jit, value, InvalidGPRReg);
</ins><span class="cx">                 jit.popToRestore(scratchTag);
</span><span class="cx">             } else
</span><del>-                profile.emitReportValue(jit, exit.m_jsValueSource.regs());
</del><ins>+                profile.emitReportValue(jit, exit.m_jsValueSource.regs(), InvalidGPRReg);
</ins><span class="cx"> #endif // USE(JSVALUE64)
</span><span class="cx">         }
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -89,7 +89,6 @@
</span><span class="cx"> #include "TypedArrayInlines.h"
</span><span class="cx"> #include "VMInlines.h"
</span><span class="cx"> #include <wtf/InlineASM.h>
</span><del>-#include <wtf/Variant.h>
</del><span class="cx"> 
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="lines">@@ -224,56 +223,6 @@
</span><span class="cx">     baseValue.putInline(globalObject, ident, putValue, slot);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template<typename BigIntOperation, typename NumberOperation>
-static ALWAYS_INLINE EncodedJSValue binaryOp(JSGlobalObject* globalObject, VM& vm, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BigIntOperation&& bigIntOp, NumberOperation&& numberOp, const char* errorMessage)
-{
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    JSValue op1 = JSValue::decode(encodedOp1);
-    JSValue op2 = JSValue::decode(encodedOp2);
-
-    auto leftNumeric = op1.toNumeric(globalObject);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    auto rightNumeric = op2.toNumeric(globalObject);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
-            RELEASE_AND_RETURN(scope, JSValue::encode(bigIntOp(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric))));
-
-        return throwVMTypeError(globalObject, scope, errorMessage);
-    }
-
-    scope.release();
-
-    return JSValue::encode(jsNumber(numberOp(WTF::get<double>(leftNumeric), WTF::get<double>(rightNumeric))));
-}
-
-template<typename BigIntOperation, typename Int32Operation>
-static ALWAYS_INLINE EncodedJSValue bitwiseBinaryOp(JSGlobalObject* globalObject, VM& vm, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2, BigIntOperation&& bigIntOp, Int32Operation&& int32Op, const char* errorMessage)
-{
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    JSValue op1 = JSValue::decode(encodedOp1);
-    JSValue op2 = JSValue::decode(encodedOp2);
-
-    auto leftNumeric = op1.toBigIntOrInt32(globalObject);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    auto rightNumeric = op2.toBigIntOrInt32(globalObject);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric))
-            RELEASE_AND_RETURN(scope, JSValue::encode(bigIntOp(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric))));
-
-        return throwVMTypeError(globalObject, scope, errorMessage);
-    }
-
-    scope.release();
-
-    return JSValue::encode(jsNumber(int32Op(WTF::get<int32_t>(leftNumeric), WTF::get<int32_t>(rightNumeric))));
-}
-
</del><span class="cx"> static ALWAYS_INLINE EncodedJSValue parseIntResult(double input)
</span><span class="cx"> {
</span><span class="cx">     int asInt = static_cast<int>(input);
</span><span class="lines">@@ -473,71 +422,34 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx"> 
</span><del>-    auto bigIntOp = [] (JSGlobalObject* globalObject, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
-        return JSBigInt::remainder(globalObject, left, right);
-    };
-
-    auto numberOp = [] (double left, double right) -> double {
-        return jsMod(left, right);
-    };
-
-    return binaryOp(globalObject, vm, encodedOp1, encodedOp2, bigIntOp, numberOp, "Invalid mix of BigInt and other type in remainder operation.");
</del><ins>+    return JSValue::encode(jsRemainder(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-EncodedJSValue JIT_OPERATION operationInc(JSGlobalObject* globalObject, EncodedJSValue encodedOp1)
</del><ins>+EncodedJSValue JIT_OPERATION operationInc(JSGlobalObject* globalObject, EncodedJSValue encodedOp)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><del>-    auto scope = DECLARE_THROW_SCOPE(vm);
</del><span class="cx"> 
</span><del>-    JSValue op1 = JSValue::decode(encodedOp1);
-
-    auto operandNumeric = op1.toNumeric(globalObject);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-
-    if (WTF::holds_alternative<JSBigInt*>(operandNumeric))
-        RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::inc(globalObject, WTF::get<JSBigInt*>(operandNumeric))));
-
-    double value = WTF::get<double>(operandNumeric);
-    return JSValue::encode(jsNumber(value + 1));
</del><ins>+    return JSValue::encode(jsInc(globalObject, JSValue::decode(encodedOp)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-EncodedJSValue JIT_OPERATION operationDec(JSGlobalObject* globalObject, EncodedJSValue encodedOp1)
</del><ins>+EncodedJSValue JIT_OPERATION operationDec(JSGlobalObject* globalObject, EncodedJSValue encodedOp)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><del>-    auto scope = DECLARE_THROW_SCOPE(vm);
</del><span class="cx"> 
</span><del>-    JSValue op1 = JSValue::decode(encodedOp1);
-
-    auto operandNumeric = op1.toNumeric(globalObject);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-
-    if (WTF::holds_alternative<JSBigInt*>(operandNumeric))
-        RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::dec(globalObject, WTF::get<JSBigInt*>(operandNumeric))));
-
-    double value = WTF::get<double>(operandNumeric);
-    return JSValue::encode(jsNumber(value - 1));
</del><ins>+    return JSValue::encode(jsDec(globalObject, JSValue::decode(encodedOp)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-EncodedJSValue JIT_OPERATION operationValueBitNot(JSGlobalObject* globalObject, EncodedJSValue encodedOp1)
</del><ins>+EncodedJSValue JIT_OPERATION operationValueBitNot(JSGlobalObject* globalObject, EncodedJSValue encodedOp)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><del>-    auto scope = DECLARE_THROW_SCOPE(vm);
</del><span class="cx"> 
</span><del>-    JSValue op1 = JSValue::decode(encodedOp1);
-
-    auto operandNumeric = op1.toBigIntOrInt32(globalObject);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-
-    if (WTF::holds_alternative<JSBigInt*>(operandNumeric))
-        RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::bitwiseNot(globalObject, WTF::get<JSBigInt*>(operandNumeric))));
-
-    return JSValue::encode(jsNumber(~WTF::get<int32_t>(operandNumeric)));
</del><ins>+    return JSValue::encode(jsBitwiseNot(globalObject, JSValue::decode(encodedOp)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationValueBitAnd(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
</span><span class="lines">@@ -546,15 +458,7 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx"> 
</span><del>-    auto bigIntOp = [] (JSGlobalObject* globalObject, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
-        return JSBigInt::bitwiseAnd(globalObject, left, right);
-    };
-
-    auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
-        return left & right;
-    };
-
-    return bitwiseBinaryOp(globalObject, vm, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'and' operation."_s);
</del><ins>+    return JSValue::encode(jsBitwiseAnd(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationValueBitOr(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
</span><span class="lines">@@ -563,15 +467,7 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx"> 
</span><del>-    auto bigIntOp = [] (JSGlobalObject* globalObject, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
-        return JSBigInt::bitwiseOr(globalObject, left, right);
-    };
-
-    auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
-        return left | right;
-    };
-
-    return bitwiseBinaryOp(globalObject, vm, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'or' operation."_s);
</del><ins>+    return JSValue::encode(jsBitwiseOr(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationValueBitXor(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
</span><span class="lines">@@ -580,15 +476,7 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx"> 
</span><del>-    auto bigIntOp = [] (JSGlobalObject* globalObject, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
-        return JSBigInt::bitwiseXor(globalObject, left, right);
-    };
-
-    auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
-        return left ^ right;
-    };
-
-    return bitwiseBinaryOp(globalObject, vm, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in bitwise 'xor' operation."_s);
</del><ins>+    return JSValue::encode(jsBitwiseXor(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationValueBitLShift(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
</span><span class="lines">@@ -597,15 +485,7 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx"> 
</span><del>-    auto bigIntOp = [] (JSGlobalObject* globalObject, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
-        return JSBigInt::leftShift(globalObject, left, right);
-    };
-
-    auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
-        return left << (right & 0x1f);
-    };
-
-    return bitwiseBinaryOp(globalObject, vm, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in left shift operation."_s);
</del><ins>+    return JSValue::encode(jsLShift(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationValueBitRShift(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
</span><span class="lines">@@ -614,15 +494,7 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx"> 
</span><del>-    auto bigIntOp = [] (JSGlobalObject* globalObject, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
-        return JSBigInt::signedRightShift(globalObject, left, right);
-    };
-
-    auto int32Op = [] (int32_t left, int32_t right) -> int32_t {
-        return left >> (right & 0x1f);
-    };
-
-    return bitwiseBinaryOp(globalObject, vm, encodedOp1, encodedOp2, bigIntOp, int32Op, "Invalid mix of BigInt and other type in signed right shift operation."_s);
</del><ins>+    return JSValue::encode(jsRShift(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationValueBitURShift(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
</span><span class="lines">@@ -660,15 +532,7 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx"> 
</span><del>-    auto bigIntOp = [] (JSGlobalObject* globalObject, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
-        return JSBigInt::divide(globalObject, left, right);
-    };
-
-    auto numberOp = [] (double left, double right) -> double {
-        return left / right;
-    };
-
-    return binaryOp(globalObject, vm, encodedOp1, encodedOp2, bigIntOp, numberOp, "Invalid mix of BigInt and other type in division operation.");
</del><ins>+    return JSValue::encode(jsDiv(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationValuePow(JSGlobalObject* globalObject, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
</span><span class="lines">@@ -677,15 +541,7 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx"> 
</span><del>-    auto bigIntOp = [] (JSGlobalObject* globalObject, JSBigInt* left, JSBigInt* right) -> JSBigInt* {
-        return JSBigInt::exponentiate(globalObject, left, right);
-    };
-
-    auto numberOp = [] (double left, double right) -> double {
-        return operationMathPow(left, right);
-    };
-
-    return binaryOp(globalObject, vm, encodedOp1, encodedOp2, bigIntOp, numberOp, "Invalid mix of BigInt and other type in exponentiation operation."_s);
</del><ins>+    return JSValue::encode(jsPow(globalObject, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> double JIT_OPERATION operationArithAbs(JSGlobalObject* globalObject, EncodedJSValue encodedOp1)
</span><span class="lines">@@ -1482,7 +1338,7 @@
</span><span class="cx">     RELEASE_AND_RETURN(scope, regexp->test(globalObject, input));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationSubBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationSubHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1494,7 +1350,7 @@
</span><span class="cx">     return JSBigInt::sub(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationBitNotBigInt(JSGlobalObject* globalObject, JSCell* op1)
</del><ins>+JSCell* JIT_OPERATION operationBitNotHeapBigInt(JSGlobalObject* globalObject, JSCell* op1)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1505,7 +1361,7 @@
</span><span class="cx">     return JSBigInt::bitwiseNot(globalObject, operand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationMulBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationMulHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1517,7 +1373,7 @@
</span><span class="cx">     return JSBigInt::multiply(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx">     
</span><del>-JSCell* JIT_OPERATION operationModBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationModHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1529,7 +1385,7 @@
</span><span class="cx">     return JSBigInt::remainder(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationDivBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationDivHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1541,7 +1397,7 @@
</span><span class="cx">     return JSBigInt::divide(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationPowBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationPowHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1553,7 +1409,7 @@
</span><span class="cx">     return JSBigInt::exponentiate(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationBitAndBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationBitAndHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1565,7 +1421,7 @@
</span><span class="cx">     return JSBigInt::bitwiseAnd(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationBitLShiftBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationBitLShiftHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1577,7 +1433,7 @@
</span><span class="cx">     return JSBigInt::leftShift(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationAddBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationAddHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1589,7 +1445,7 @@
</span><span class="cx">     return JSBigInt::add(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationBitRShiftBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationBitRShiftHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1601,7 +1457,7 @@
</span><span class="cx">     return JSBigInt::signedRightShift(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationBitOrBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationBitOrHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1613,7 +1469,7 @@
</span><span class="cx">     return JSBigInt::bitwiseOr(globalObject, leftOperand, rightOperand);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSCell* JIT_OPERATION operationBitXorBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</del><ins>+JSCell* JIT_OPERATION operationBitXorHeapBigInt(JSGlobalObject* globalObject, JSCell* op1, JSCell* op2)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="lines">@@ -1631,7 +1487,7 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx">     
</span><del>-    return JSValue::strictEqualSlowCaseInline(globalObject, op1, op2);
</del><ins>+    return JSValue::strictEqualForCells(globalObject, op1, op2);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> size_t JIT_OPERATION operationSameValue(JSGlobalObject* globalObject, EncodedJSValue arg1, EncodedJSValue arg2)
</span><span class="lines">@@ -1676,10 +1532,7 @@
</span><span class="cx">     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
</span><span class="cx">     JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
</span><span class="cx"> 
</span><del>-    auto variant = JSValue::decode(value).toNumeric(globalObject);
-    if (WTF::holds_alternative<JSBigInt*>(variant))
-        return JSValue::encode(WTF::get<JSBigInt*>(variant));
-    return JSValue::encode(jsNumber(WTF::get<double>(variant)));
</del><ins>+    return JSValue::encode(JSValue::decode(value).toNumeric(globalObject));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationGetByValWithThis(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedThis, EncodedJSValue encodedSubscript)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.h  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.h     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -183,18 +183,18 @@
</span><span class="cx"> size_t JIT_OPERATION operationRegExpTest(JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
</span><span class="cx"> size_t JIT_OPERATION operationRegExpTestGeneric(JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</span><span class="cx"> size_t JIT_OPERATION operationCompareStrictEqCell(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
</span><del>-JSCell* JIT_OPERATION operationSubBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationMulBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationModBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationDivBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationPowBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationBitAndBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationBitNotBigInt(JSGlobalObject*, JSCell* op1) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationBitOrBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationBitLShiftBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationAddBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationBitRShiftBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
-JSCell* JIT_OPERATION operationBitXorBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
</del><ins>+JSCell* JIT_OPERATION operationSubHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationMulHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationModHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationDivHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationPowHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationBitAndHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationBitNotHeapBigInt(JSGlobalObject*, JSCell* op1) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationBitOrHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationBitLShiftHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationAddHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationBitRShiftHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
+JSCell* JIT_OPERATION operationBitXorHeapBigInt(JSGlobalObject*, JSCell* op1, JSCell* op2) WTF_INTERNAL;
</ins><span class="cx"> size_t JIT_OPERATION operationSameValue(JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</span><span class="cx"> JSCell* JIT_OPERATION operationCreateActivationDirect(VM*, Structure*, JSScope*, SymbolTable*, EncodedJSValue);
</span><span class="cx"> JSCell* JIT_OPERATION operationCreateDirectArguments(VM*, Structure*, uint32_t length, uint32_t minCapacity);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -532,7 +532,19 @@
</span><span class="cx">                     changed |= mergePrediction(SpecSymbol);
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><del>-                
</del><ins>+
+#if USE(BIGINT32)
+                if (node->child1()->shouldSpeculateBigInt32()) {
+                    changed |= mergePrediction(SpecBigInt32);
+                    break;
+                }
+#endif
+
+                if (node->child1()->shouldSpeculateHeapBigInt()) {
+                    changed |= mergePrediction(SpecHeapBigInt);
+                    break;
+                }
+
</ins><span class="cx">                 if (node->child1()->shouldSpeculateBigInt()) {
</span><span class="cx">                     changed |= mergePrediction(SpecBigInt);
</span><span class="cx">                     break;
</span><span class="lines">@@ -1004,6 +1016,7 @@
</span><span class="cx">         case IsUndefinedOrNull:
</span><span class="cx">         case IsBoolean:
</span><span class="cx">         case IsNumber:
</span><ins>+        case IsBigInt:
</ins><span class="cx">         case NumberIsInteger:
</span><span class="cx">         case IsObject:
</span><span class="cx">         case IsObjectOrNull:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -79,7 +79,9 @@
</span><span class="cx">         case StringUse:
</span><span class="cx">         case StringOrOtherUse:
</span><span class="cx">         case SymbolUse:
</span><del>-        case BigIntUse:
</del><ins>+        case AnyBigIntUse:
+        case HeapBigIntUse:
+        case BigInt32Use:
</ins><span class="cx">         case StringObjectUse:
</span><span class="cx">         case StringOrStringObjectUse:
</span><span class="cx">         case NotStringVarUse:
</span><span class="lines">@@ -263,6 +265,7 @@
</span><span class="cx">     case IsUndefinedOrNull:
</span><span class="cx">     case IsBoolean:
</span><span class="cx">     case IsNumber:
</span><ins>+    case IsBigInt:
</ins><span class="cx">     case NumberIsInteger:
</span><span class="cx">     case IsObject:
</span><span class="cx">     case IsObjectOrNull:
</span><span class="lines">@@ -676,10 +679,10 @@
</span><span class="cx">     case ValueDiv:
</span><span class="cx">     case ValueMod:
</span><span class="cx">     case ValuePow:
</span><del>-        return node->isBinaryUseKind(BigIntUse);
</del><ins>+        return node->isBinaryUseKind(AnyBigIntUse) || node->isBinaryUseKind(BigInt32Use) || node->isBinaryUseKind(HeapBigIntUse);
</ins><span class="cx"> 
</span><span class="cx">     case ValueBitNot:
</span><del>-        return node->child1().useKind() == BigIntUse;
</del><ins>+        return node->child1().useKind() == AnyBigIntUse || node->child1().useKind() == BigInt32Use || node->child1().useKind() == HeapBigIntUse;
</ins><span class="cx"> 
</span><span class="cx">     case LastNodeType:
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -368,6 +368,13 @@
</span><span class="cx">     speculationCheck(exitKind, source, edge.node(), jumpToFail);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeculativeJIT::typeCheck(JSValueSource source, Edge edge, SpeculatedType typesPassedThrough, MacroAssembler::JumpList jumpListToFail, ExitKind exitKind)
+{
+    ASSERT(needsTypeCheck(edge, typesPassedThrough));
+    m_interpreter.filter(edge, typesPassedThrough);
+    speculationCheck(exitKind, source, edge.node(), jumpListToFail);
+}
+
</ins><span class="cx"> RegisterSet SpeculativeJIT::usedRegisters()
</span><span class="cx"> {
</span><span class="cx">     RegisterSet result;
</span><span class="lines">@@ -1708,6 +1715,10 @@
</span><span class="cx"> 
</span><span class="cx">         if (node->isBinaryUseKind(Int32Use))
</span><span class="cx">             compilePeepHoleInt32Branch(node, branchNode, condition);
</span><ins>+#if USE(BIGINT32)
+        else if (node->isBinaryUseKind(BigInt32Use) && (condition == MacroAssembler::Equal || condition == MacroAssembler::NotEqual))
+            compilePeepHoleBigInt32Branch(node, branchNode, condition);
+#endif
</ins><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">         else if (node->isBinaryUseKind(Int52RepUse))
</span><span class="cx">             compilePeepHoleInt52Branch(node, branchNode, condition);
</span><span class="lines">@@ -3535,17 +3546,38 @@
</span><span class="cx"> {
</span><span class="cx">     Edge& child1 = node->child1();
</span><span class="cx"> 
</span><del>-    if (child1.useKind() == BigIntUse) {
</del><ins>+#if USE(BIGINT32)
+    if (child1.useKind() == BigInt32Use) {
+        SpeculateBigInt32Operand operand(this, child1);
+        GPRTemporary result(this);
+        GPRReg resultGPR = result.gpr();
+
+        // The following trick relies on details of the representation of BigInt32, and will have to be updated if we move bits around.
+        static_assert(JSValue::BigInt32Tag == 0x12);
+        static_assert(JSValue::BigInt32Mask == 0xfffe000000000012);
+        constexpr uint64_t maskForBigInt32Bits = 0x0000ffffffff0000;
+        static_assert(!(JSValue::BigInt32Mask & maskForBigInt32Bits));
+        m_jit.move(TrustedImm64(maskForBigInt32Bits), resultGPR);
+        m_jit.xor64(operand.gpr(), resultGPR);
+
+        jsValueResult(resultGPR, node);
+
+        return;
+    }
+    // FIXME: add support for mixed BigInt32 / HeapBigInt
+#endif
+
+    if (child1.useKind() == HeapBigIntUse) {
</ins><span class="cx">         SpeculateCellOperand operand(this, child1);
</span><span class="cx">         GPRReg operandGPR = operand.gpr();
</span><span class="cx"> 
</span><del>-        speculateBigInt(child1, operandGPR);
</del><ins>+        speculateHeapBigInt(child1, operandGPR);
</ins><span class="cx"> 
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><span class="cx">         GPRReg resultGPR = result.gpr();
</span><span class="cx"> 
</span><del>-        callOperation(operationBitNotBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), operandGPR);
</del><ins>+        callOperation(operationBitNotHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), operandGPR);
</ins><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         cellResult(resultGPR, node);
</span><span class="cx"> 
</span><span class="lines">@@ -3552,7 +3584,9 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    JSValueOperand operand(this, child1);
</del><ins>+    ASSERT(child1.useKind() == UntypedUse || child1.useKind() == AnyBigIntUse);
+    JSValueOperand operand(this, child1, ManualOperandSpeculation);
+    speculate(node, child1); // Required for the AnyBigIntUse case
</ins><span class="cx">     JSValueRegs operandRegs = operand.jsValueRegs();
</span><span class="cx"> 
</span><span class="cx">     flushRegisters();
</span><span class="lines">@@ -3580,14 +3614,18 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template<typename SnippetGenerator, J_JITOperation_GJJ snippetSlowPathFunction>
</span><del>-void SpeculativeJIT::emitUntypedBitOp(Node* node)
</del><ins>+void SpeculativeJIT::emitUntypedOrAnyBigIntBitOp(Node* node)
</ins><span class="cx"> {
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><ins>+    ASSERT(leftChild.useKind() == UntypedUse || leftChild.useKind() == AnyBigIntUse || rightChild.useKind() == UntypedUse || rightChild.useKind() == AnyBigIntUse);
+
</ins><span class="cx">     if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
</span><del>-        JSValueOperand left(this, leftChild);
-        JSValueOperand right(this, rightChild);
</del><ins>+        JSValueOperand left(this, leftChild, ManualOperandSpeculation);
+        JSValueOperand right(this, rightChild, ManualOperandSpeculation);
+        speculate(node, leftChild);
+        speculate(node, rightChild);
</ins><span class="cx">         JSValueRegs leftRegs = left.jsValueRegs();
</span><span class="cx">         JSValueRegs rightRegs = right.jsValueRegs();
</span><span class="cx"> 
</span><span class="lines">@@ -3632,11 +3670,13 @@
</span><span class="cx">     RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
</span><span class="cx"> 
</span><span class="cx">     if (!leftOperand.isConst()) {
</span><del>-        left.emplace(this, leftChild);
</del><ins>+        left.emplace(this, leftChild, ManualOperandSpeculation);
+        speculate(node, leftChild); // Required for AnyBigIntUse
</ins><span class="cx">         leftRegs = left->jsValueRegs();
</span><span class="cx">     }
</span><span class="cx">     if (!rightOperand.isConst()) {
</span><del>-        right.emplace(this, rightChild);
</del><ins>+        right.emplace(this, rightChild, ManualOperandSpeculation);
+        speculate(node, rightChild); // Required for AnyBigIntUse
</ins><span class="cx">         rightRegs = right->jsValueRegs();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -3672,52 +3712,84 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
</del><ins>+#if USE(BIGINT32)
+    if (leftChild.useKind() == BigInt32Use && rightChild.useKind() == BigInt32Use) {
+        SpeculateBigInt32Operand left(this, leftChild);
+        SpeculateBigInt32Operand right(this, rightChild);
+        GPRTemporary result(this);
+        GPRReg resultGPR = result.gpr();
+
+        m_jit.move(left.gpr(), resultGPR);
+
</ins><span class="cx">         switch (op) {
</span><span class="cx">         case ValueBitAnd:
</span><del>-            emitUntypedBitOp<JITBitAndGenerator, operationValueBitAnd>(node);
-            return;
</del><ins>+            // No need to unbox/box: bitAnd does not interfere with the encoding of BigInt32
+            m_jit.and64(right.gpr(), resultGPR);
+            break;
+        case ValueBitOr:
+            // No need to unbox/box: bitOr does not interfere with the encoding of BigInt32
+            m_jit.or64(right.gpr(), resultGPR);
+            break;
</ins><span class="cx">         case ValueBitXor:
</span><del>-            emitUntypedBitOp<JITBitXorGenerator, operationValueBitXor>(node);
-            return;
-        case ValueBitOr:
-            emitUntypedBitOp<JITBitOrGenerator, operationValueBitOr>(node);
-            return;
</del><ins>+            // BitXor removes the tag, so we must add it back after doing the operation
+            m_jit.xor64(right.gpr(), resultGPR);
+            m_jit.or64(TrustedImm32(JSValue::BigInt32Tag), resultGPR);
+            break;
</ins><span class="cx">         default:
</span><span class="cx">             RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">         }
</span><ins>+
+        jsValueResult(resultGPR, node);
+        return;
</ins><span class="cx">     }
</span><del>-    
-    ASSERT(leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse);
-    
-    SpeculateCellOperand left(this, node->child1());
-    SpeculateCellOperand right(this, node->child2());
-    GPRReg leftGPR = left.gpr();
-    GPRReg rightGPR = right.gpr();
</del><ins>+    // FIXME: add support for mixed BigInt32 / HeapBigInt
+#endif
</ins><span class="cx"> 
</span><del>-    speculateBigInt(leftChild, leftGPR);
-    speculateBigInt(rightChild, rightGPR);
</del><ins>+    if (leftChild.useKind() == HeapBigIntUse && rightChild.useKind() == HeapBigIntUse) {
+        SpeculateCellOperand left(this, node->child1());
+        SpeculateCellOperand right(this, node->child2());
+        GPRReg leftGPR = left.gpr();
+        GPRReg rightGPR = right.gpr();
</ins><span class="cx"> 
</span><del>-    flushRegisters();
-    GPRFlushedCallResult result(this);
-    GPRReg resultGPR = result.gpr();
</del><ins>+        speculateHeapBigInt(leftChild, leftGPR);
+        speculateHeapBigInt(rightChild, rightGPR);
</ins><span class="cx"> 
</span><ins>+        flushRegisters();
+        GPRFlushedCallResult result(this);
+        GPRReg resultGPR = result.gpr();
+
+        switch (op) {
+        case ValueBitAnd:
+            callOperation(operationBitAndHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
+            break;
+        case ValueBitXor:
+            callOperation(operationBitXorHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
+            break;
+        case ValueBitOr:
+            callOperation(operationBitOrHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        m_jit.exceptionCheck();
+        cellResult(resultGPR, node);
+        return;
+    }
+
</ins><span class="cx">     switch (op) {
</span><span class="cx">     case ValueBitAnd:
</span><del>-        callOperation(operationBitAndBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
-        break;
</del><ins>+        emitUntypedOrAnyBigIntBitOp<JITBitAndGenerator, operationValueBitAnd>(node);
+        return;
</ins><span class="cx">     case ValueBitXor:
</span><del>-        callOperation(operationBitXorBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
-        break;
</del><ins>+        emitUntypedOrAnyBigIntBitOp<JITBitXorGenerator, operationValueBitXor>(node);
+        return;
</ins><span class="cx">     case ValueBitOr:
</span><del>-        callOperation(operationBitOrBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
-        break;
</del><ins>+        emitUntypedOrAnyBigIntBitOp<JITBitOrGenerator, operationValueBitOr>(node);
+        return;
</ins><span class="cx">     default:
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><del>-
-    m_jit.exceptionCheck();
-    cellResult(resultGPR, node);
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::compileBitwiseOp(Node* node)
</span><span class="lines">@@ -3757,7 +3829,7 @@
</span><span class="cx">     strictInt32Result(result.gpr(), node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::emitUntypedRightShiftBitOp(Node* node)
</del><ins>+void SpeculativeJIT::emitUntypedOrBigIntRightShiftBitOp(Node* node)
</ins><span class="cx"> {
</span><span class="cx">     J_JITOperation_GJJ snippetSlowPathFunction = node->op() == ValueBitRShift
</span><span class="cx">         ? operationValueBitRShift : operationValueBitURShift;
</span><span class="lines">@@ -3767,9 +3839,11 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
-        JSValueOperand left(this, leftChild);
-        JSValueOperand right(this, rightChild);
</del><ins>+    if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node()) || node->isBinaryUseKind(BigInt32Use) || node->isBinaryUseKind(AnyBigIntUse)) {
+        JSValueOperand left(this, leftChild, ManualOperandSpeculation);
+        JSValueOperand right(this, rightChild, ManualOperandSpeculation);
+        speculate(node, leftChild);
+        speculate(node, rightChild);
</ins><span class="cx">         JSValueRegs leftRegs = left.jsValueRegs();
</span><span class="cx">         JSValueRegs rightRegs = right.jsValueRegs();
</span><span class="cx"> 
</span><span class="lines">@@ -3861,27 +3935,27 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (node->binaryUseKind() == BigIntUse) {
</del><ins>+    // FIXME: support BigInt32
+    if (node->binaryUseKind() == HeapBigIntUse) {
</ins><span class="cx">         SpeculateCellOperand left(this, leftChild);
</span><span class="cx">         SpeculateCellOperand right(this, rightChild);
</span><span class="cx">         GPRReg leftGPR = left.gpr();
</span><span class="cx">         GPRReg rightGPR = right.gpr();
</span><span class="cx"> 
</span><del>-        speculateBigInt(leftChild, leftGPR);
-        speculateBigInt(rightChild, rightGPR);
</del><ins>+        speculateHeapBigInt(leftChild, leftGPR);
+        speculateHeapBigInt(rightChild, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><span class="cx">         GPRReg resultGPR = result.gpr();
</span><span class="cx"> 
</span><del>-        callOperation(operationBitLShiftBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</del><ins>+        callOperation(operationBitLShiftHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</ins><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         cellResult(resultGPR, node);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ASSERT(leftChild.useKind() == UntypedUse && rightChild.useKind() == UntypedUse);
-    emitUntypedBitOp<JITLeftShiftGenerator, operationValueBitLShift>(node);
</del><ins>+    emitUntypedOrAnyBigIntBitOp<JITLeftShiftGenerator, operationValueBitLShift>(node);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::compileValueBitRShift(Node* node)
</span><span class="lines">@@ -3889,19 +3963,20 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (node->isBinaryUseKind(BigIntUse)) {
</del><ins>+    // FIXME: support BigInt32
+    if (node->isBinaryUseKind(HeapBigIntUse)) {
</ins><span class="cx">         SpeculateCellOperand left(this, leftChild);
</span><span class="cx">         SpeculateCellOperand right(this, rightChild);
</span><span class="cx">         GPRReg leftGPR = left.gpr();
</span><span class="cx">         GPRReg rightGPR = right.gpr();
</span><span class="cx"> 
</span><del>-        speculateBigInt(leftChild, leftGPR);
-        speculateBigInt(rightChild, rightGPR);
</del><ins>+        speculateHeapBigInt(leftChild, leftGPR);
+        speculateHeapBigInt(rightChild, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><span class="cx">         GPRReg resultGPR = result.gpr();
</span><del>-        callOperation(operationBitRShiftBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</del><ins>+        callOperation(operationBitRShiftHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</ins><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx"> 
</span><span class="cx">         cellResult(resultGPR, node);
</span><span class="lines">@@ -3908,8 +3983,7 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ASSERT(leftChild.useKind() == UntypedUse && rightChild.useKind() == UntypedUse);
-    emitUntypedRightShiftBitOp(node);
</del><ins>+    emitUntypedOrBigIntRightShiftBitOp(node);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::compileShiftOp(Node* node)
</span><span class="lines">@@ -3920,7 +3994,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (leftChild.useKind() == UntypedUse || rightChild.useKind() == UntypedUse) {
</span><span class="cx">         RELEASE_ASSERT(op == BitURShift);
</span><del>-        emitUntypedRightShiftBitOp(node);
</del><ins>+        emitUntypedOrBigIntRightShiftBitOp(node);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -3950,19 +4024,67 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (node->isBinaryUseKind(BigIntUse)) {
-        SpeculateCellOperand left(this, node->child1());
-        SpeculateCellOperand right(this, node->child2());
</del><ins>+#if USE(BIGINT32)
+    if (node->isBinaryUseKind(BigInt32Use)) {
+        SpeculateBigInt32Operand left(this, leftChild);
+        SpeculateBigInt32Operand right(this, rightChild);
+
+        // FIXME: do we really need this extra register, or can we mutate left/right ?
+        // FIXME: also, look into Reuse and other tricks for a more efficient generated code.
+        GPRTemporary result(this);
+        GPRReg resultGPR = result.gpr();
+        GPRTemporary temp(this);
+        GPRReg tempGPR = temp.gpr();
+
+        m_jit.move(left.gpr(), resultGPR);
+        m_jit.unboxBigInt32(resultGPR);
+        m_jit.move(right.gpr(), tempGPR);
+        m_jit.unboxBigInt32(tempGPR);
+
+        // FIXME: add some way to eliminate the overflow check
+        MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, resultGPR, tempGPR, resultGPR);
+
+        speculationCheck(Overflow, JSValueRegs(), 0, check);
+
+        m_jit.boxBigInt32(resultGPR);
+        jsValueResult(resultGPR, node);
+        return;
+    }
+
+    if (node->isBinaryUseKind(AnyBigIntUse)) {
+        JSValueOperand left(this, leftChild, ManualOperandSpeculation);
+        JSValueOperand right(this, rightChild, ManualOperandSpeculation);
+        speculate(node, leftChild);
+        speculate(node, rightChild);
+        JSValueRegs leftRegs = left.jsValueRegs();
+        JSValueRegs rightRegs = right.jsValueRegs();
+
+        flushRegisters();
+        JSValueRegsFlushedCallResult result(this);
+        JSValueRegs resultRegs = result.regs();
+        // FIXME: call a more specialized function
+        callOperation(operationValueAddNotNumber, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
+        m_jit.exceptionCheck();
+
+        jsValueResult(resultRegs, node);
+        return;
+    }
+    // FIXME: add support for mixed BigInt32/HeapBigInt
+#endif // USE(BIGINT32)
+
+    if (node->isBinaryUseKind(HeapBigIntUse)) {
+        SpeculateCellOperand left(this, leftChild);
+        SpeculateCellOperand right(this, rightChild);
</ins><span class="cx">         GPRReg leftGPR = left.gpr();
</span><span class="cx">         GPRReg rightGPR = right.gpr();
</span><span class="cx"> 
</span><del>-        speculateBigInt(leftChild, leftGPR);
-        speculateBigInt(rightChild, rightGPR);
</del><ins>+        speculateHeapBigInt(leftChild, leftGPR);
+        speculateHeapBigInt(rightChild, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><span class="cx">         GPRReg resultGPR = result.gpr();
</span><del>-        callOperation(operationAddBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</del><ins>+        callOperation(operationAddHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</ins><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx"> 
</span><span class="cx">         cellResult(resultGPR, node);
</span><span class="lines">@@ -4008,44 +4130,90 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (node->binaryUseKind() == UntypedUse) {
-#if USE(JSVALUE64)
-        bool needsScratchGPRReg = true;
-        bool needsScratchFPRReg = false;
-#else
-        bool needsScratchGPRReg = true;
-        bool needsScratchFPRReg = true;
-#endif
</del><ins>+#if USE(BIGINT32)
+    if (node->binaryUseKind() == BigInt32Use) {
+        SpeculateBigInt32Operand left(this, node->child1());
+        SpeculateBigInt32Operand right(this, node->child2());
</ins><span class="cx"> 
</span><del>-        CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
-        BytecodeIndex bytecodeIndex = node->origin.semantic.bytecodeIndex();
-        BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeIndex(bytecodeIndex);
-        JITSubIC* subIC = m_jit.codeBlock()->addJITSubIC(arithProfile);
-        auto repatchingFunction = operationValueSubOptimize;
-        auto nonRepatchingFunction = operationValueSub;
</del><ins>+        // FIXME: do we really need this extra register, or can we mutate left/right ?
+        // FIXME: also, look into Reuse and other tricks for a more efficient generated code.
+        GPRTemporary result(this);
+        GPRReg resultGPR = result.gpr();
+        GPRTemporary temp(this);
+        GPRReg tempGPR = temp.gpr();
</ins><span class="cx"> 
</span><del>-        compileMathIC(node, subIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
</del><ins>+        m_jit.move(left.gpr(), resultGPR);
+        m_jit.unboxBigInt32(resultGPR);
+        m_jit.move(right.gpr(), tempGPR);
+        m_jit.unboxBigInt32(tempGPR);
+
+        // FIXME: add some way to eliminate the overflow check
+        MacroAssembler::Jump check = m_jit.branchSub32(MacroAssembler::Overflow, resultGPR, tempGPR, resultGPR);
+
+        speculationCheck(Overflow, JSValueRegs(), 0, check);
+
+        m_jit.boxBigInt32(resultGPR);
+        jsValueResult(resultGPR, node);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><ins>+    // FIXME: add support for mixed BigInt32/HeapBigInt
</ins><span class="cx"> 
</span><del>-    ASSERT(leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse);
</del><ins>+    // FIXME: why do compileValueAdd/compileValueMul use isKnownNotNumber but not ValueSub?
+    if (node->binaryUseKind() == AnyBigIntUse) {
+        JSValueOperand left(this, leftChild, ManualOperandSpeculation);
+        JSValueOperand right(this, rightChild, ManualOperandSpeculation);
+        speculateAnyBigInt(leftChild);
+        speculateAnyBigInt(rightChild);
+        JSValueRegs leftRegs = left.jsValueRegs();
+        JSValueRegs rightRegs = right.jsValueRegs();
</ins><span class="cx"> 
</span><del>-    SpeculateCellOperand left(this, node->child1());
-    SpeculateCellOperand right(this, node->child2());
-    GPRReg leftGPR = left.gpr();
-    GPRReg rightGPR = right.gpr();
</del><ins>+        flushRegisters();
+        JSValueRegsFlushedCallResult result(this);
+        JSValueRegs resultRegs = result.regs();
+        callOperation(operationValueSub, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftRegs, rightRegs);
+        m_jit.exceptionCheck();
</ins><span class="cx"> 
</span><del>-    speculateBigInt(leftChild, leftGPR);
-    speculateBigInt(rightChild, rightGPR);
</del><ins>+        jsValueResult(resultRegs, node);
+        return;
+    }
+#endif // USE(BIGINT32)
</ins><span class="cx"> 
</span><del>-    flushRegisters();
-    GPRFlushedCallResult result(this);
-    GPRReg resultGPR = result.gpr();
</del><ins>+    if (node->binaryUseKind() == HeapBigIntUse) {
+        SpeculateCellOperand left(this, node->child1());
+        SpeculateCellOperand right(this, node->child2());
+        GPRReg leftGPR = left.gpr();
+        GPRReg rightGPR = right.gpr();
</ins><span class="cx"> 
</span><del>-    callOperation(operationSubBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</del><ins>+        speculateHeapBigInt(leftChild, leftGPR);
+        speculateHeapBigInt(rightChild, rightGPR);
</ins><span class="cx"> 
</span><del>-    m_jit.exceptionCheck();
-    cellResult(resultGPR, node);
</del><ins>+        flushRegisters();
+        GPRFlushedCallResult result(this);
+        GPRReg resultGPR = result.gpr();
+
+        callOperation(operationSubHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
+
+        m_jit.exceptionCheck();
+        cellResult(resultGPR, node);
+        return;
+    }
+
+#if USE(JSVALUE64)
+    bool needsScratchGPRReg = true;
+    bool needsScratchFPRReg = false;
+#else
+    bool needsScratchGPRReg = true;
+    bool needsScratchFPRReg = true;
+#endif
+
+    CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
+    BytecodeIndex bytecodeIndex = node->origin.semantic.bytecodeIndex();
+    BinaryArithProfile* arithProfile = baselineCodeBlock->binaryArithProfileForBytecodeIndex(bytecodeIndex);
+    JITSubIC* subIC = m_jit.codeBlock()->addJITSubIC(arithProfile);
+    auto repatchingFunction = operationValueSubOptimize;
+    auto nonRepatchingFunction = operationValueSub;
+
+    compileMathIC(node, subIC, needsScratchGPRReg, needsScratchFPRReg, repatchingFunction, nonRepatchingFunction);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template <typename Generator, typename RepatchingFunction, typename NonRepatchingFunction>
</span><span class="lines">@@ -4630,6 +4798,7 @@
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::compileValueNegate(Node* node)
</span><span class="cx"> {
</span><ins>+    // FIXME: add a fast path, at least for BigInt32, but probably also for HeapBigInt here.
</ins><span class="cx">     CodeBlock* baselineCodeBlock = m_jit.graph().baselineCodeBlockFor(node->origin.semantic);
</span><span class="cx">     BytecodeIndex bytecodeIndex = node->origin.semantic.bytecodeIndex();
</span><span class="cx">     UnaryArithProfile* arithProfile = baselineCodeBlock->unaryArithProfileForBytecodeIndex(bytecodeIndex);
</span><span class="lines">@@ -4810,20 +4979,50 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse) {
</del><ins>+#if USE(BIGINT32)
+    if (node->binaryUseKind() == BigInt32Use) {
+        // FIXME: the code between compileValueAdd, compileValueSub and compileValueMul for BigInt32 is nearly identical, so try to get rid of the duplication.
+        SpeculateBigInt32Operand left(this, node->child1());
+        SpeculateBigInt32Operand right(this, node->child2());
+
+        // FIXME: do we really need this extra register, or can we mutate left/right ?
+        // FIXME: also, look into Reuse and other tricks for a more efficient generated code.
+        GPRTemporary result(this);
+        GPRReg resultGPR = result.gpr();
+        GPRTemporary temp(this);
+        GPRReg tempGPR = temp.gpr();
+
+        m_jit.move(left.gpr(), resultGPR);
+        m_jit.unboxBigInt32(resultGPR);
+        m_jit.move(right.gpr(), tempGPR);
+        m_jit.unboxBigInt32(tempGPR);
+
+        // FIXME: add some way to eliminate the overflow check
+        MacroAssembler::Jump check = m_jit.branchMul32(MacroAssembler::Overflow, resultGPR, tempGPR, resultGPR);
+
+        speculationCheck(Overflow, JSValueRegs(), 0, check);
+
+        m_jit.boxBigInt32(resultGPR);
+        jsValueResult(resultGPR, node);
+        return;
+    }
+    // FIXME: add support for mixed BigInt32/HeapBigInt
+#endif
+
+    if (leftChild.useKind() == HeapBigIntUse && rightChild.useKind() == HeapBigIntUse) {
</ins><span class="cx">         SpeculateCellOperand left(this, leftChild);
</span><span class="cx">         SpeculateCellOperand right(this, rightChild);
</span><span class="cx">         GPRReg leftGPR = left.gpr();
</span><span class="cx">         GPRReg rightGPR = right.gpr();
</span><span class="cx"> 
</span><del>-        speculateBigInt(leftChild, leftGPR);
-        speculateBigInt(rightChild, rightGPR);
</del><ins>+        speculateHeapBigInt(leftChild, leftGPR);
+        speculateHeapBigInt(rightChild, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><span class="cx">         GPRReg resultGPR = result.gpr();
</span><span class="cx"> 
</span><del>-        callOperation(operationMulBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</del><ins>+        callOperation(operationMulHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         cellResult(resultGPR, node);
</span><span class="lines">@@ -4830,9 +5029,11 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
-        JSValueOperand left(this, leftChild);
-        JSValueOperand right(this, rightChild);
</del><ins>+    if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node()) || node->isBinaryUseKind(AnyBigIntUse)) {
+        JSValueOperand left(this, leftChild, ManualOperandSpeculation);
+        JSValueOperand right(this, rightChild, ManualOperandSpeculation);
+        speculate(node, leftChild);
+        speculate(node, rightChild);
</ins><span class="cx">         JSValueRegs leftRegs = left.jsValueRegs();
</span><span class="cx">         JSValueRegs rightRegs = right.jsValueRegs();
</span><span class="cx"> 
</span><span class="lines">@@ -5012,20 +5213,22 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (leftChild.useKind() == BigIntUse && rightChild.useKind() == BigIntUse) {
</del><ins>+    // FIXME: add a fast path for BigInt32. Currently we go through the slow path, because of how ugly the code for Div gets.
+
+    if (node->isBinaryUseKind(HeapBigIntUse)) {
</ins><span class="cx">         SpeculateCellOperand left(this, leftChild);
</span><span class="cx">         SpeculateCellOperand right(this, rightChild);
</span><span class="cx">         GPRReg leftGPR = left.gpr();
</span><span class="cx">         GPRReg rightGPR = right.gpr();
</span><span class="cx"> 
</span><del>-        speculateBigInt(leftChild, leftGPR);
-        speculateBigInt(rightChild, rightGPR);
</del><ins>+        speculateHeapBigInt(leftChild, leftGPR);
+        speculateHeapBigInt(rightChild, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><span class="cx">         GPRReg resultGPR = result.gpr();
</span><span class="cx"> 
</span><del>-        callOperation(operationDivBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</del><ins>+        callOperation(operationDivHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         cellResult(resultGPR, node);
</span><span class="lines">@@ -5032,9 +5235,11 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
-        JSValueOperand left(this, leftChild);
-        JSValueOperand right(this, rightChild);
</del><ins>+    if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node()) || node->isBinaryUseKind(AnyBigIntUse) || node->isBinaryUseKind(BigInt32Use)) {
+        JSValueOperand left(this, leftChild, ManualOperandSpeculation);
+        JSValueOperand right(this, rightChild, ManualOperandSpeculation);
+        speculate(node, leftChild);
+        speculate(node, rightChild);
</ins><span class="cx">         JSValueRegs leftRegs = left.jsValueRegs();
</span><span class="cx">         JSValueRegs rightRegs = right.jsValueRegs();
</span><span class="cx"> 
</span><span class="lines">@@ -5048,6 +5253,8 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ASSERT(node->isBinaryUseKind(UntypedUse));
+
</ins><span class="cx">     Optional<JSValueOperand> left;
</span><span class="cx">     Optional<JSValueOperand> right;
</span><span class="cx"> 
</span><span class="lines">@@ -5297,20 +5504,22 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (node->binaryUseKind() == BigIntUse) {
</del><ins>+    // FIXME: add a fast path for BigInt32. Currently we go through the slow path, because of how ugly the code for Mod gets.
+
+    if (node->binaryUseKind() == HeapBigIntUse) {
</ins><span class="cx">         SpeculateCellOperand left(this, leftChild);
</span><span class="cx">         SpeculateCellOperand right(this, rightChild);
</span><span class="cx">         GPRReg leftGPR = left.gpr();
</span><span class="cx">         GPRReg rightGPR = right.gpr();
</span><span class="cx"> 
</span><del>-        speculateBigInt(leftChild, leftGPR);
-        speculateBigInt(rightChild, rightGPR);
</del><ins>+        speculateHeapBigInt(leftChild, leftGPR);
+        speculateHeapBigInt(rightChild, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><span class="cx">         GPRReg resultGPR = result.gpr();
</span><span class="cx"> 
</span><del>-        callOperation(operationModBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</del><ins>+        callOperation(operationModHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         cellResult(resultGPR, node);
</span><span class="lines">@@ -5317,9 +5526,11 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse, node->binaryUseKind());
-    JSValueOperand op1(this, leftChild);
-    JSValueOperand op2(this, rightChild);
</del><ins>+    DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse || node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use, node->binaryUseKind());
+    JSValueOperand op1(this, leftChild, ManualOperandSpeculation);
+    JSValueOperand op2(this, rightChild, ManualOperandSpeculation);
+    speculate(node, leftChild);
+    speculate(node, rightChild);
</ins><span class="cx">     JSValueRegs op1Regs = op1.jsValueRegs();
</span><span class="cx">     JSValueRegs op2Regs = op2.jsValueRegs();
</span><span class="cx">     flushRegisters();
</span><span class="lines">@@ -5861,20 +6072,21 @@
</span><span class="cx">     Edge& leftChild = node->child1();
</span><span class="cx">     Edge& rightChild = node->child2();
</span><span class="cx"> 
</span><del>-    if (node->binaryUseKind() == BigIntUse) {
</del><ins>+    // FIXME: do we want a fast path for BigInt32 for Pow? I expect it would overflow pretty often.
+    if (node->binaryUseKind() == HeapBigIntUse) {
</ins><span class="cx">         SpeculateCellOperand left(this, leftChild);
</span><span class="cx">         SpeculateCellOperand right(this, rightChild);
</span><span class="cx">         GPRReg leftGPR = left.gpr();
</span><span class="cx">         GPRReg rightGPR = right.gpr();
</span><span class="cx"> 
</span><del>-        speculateBigInt(leftChild, leftGPR);
-        speculateBigInt(rightChild, rightGPR);
</del><ins>+        speculateHeapBigInt(leftChild, leftGPR);
+        speculateHeapBigInt(rightChild, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         flushRegisters();
</span><span class="cx">         GPRFlushedCallResult result(this);
</span><span class="cx">         GPRReg resultGPR = result.gpr();
</span><span class="cx"> 
</span><del>-        callOperation(operationPowBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</del><ins>+        callOperation(operationPowHeapBigInt, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), leftGPR, rightGPR);
</ins><span class="cx"> 
</span><span class="cx">         m_jit.exceptionCheck();
</span><span class="cx">         cellResult(resultGPR, node);
</span><span class="lines">@@ -5881,10 +6093,12 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse, node->binaryUseKind());
</del><ins>+    DFG_ASSERT(m_jit.graph(), node, node->binaryUseKind() == UntypedUse || node->binaryUseKind() == AnyBigIntUse || node->binaryUseKind() == BigInt32Use, node->binaryUseKind());
</ins><span class="cx"> 
</span><del>-    JSValueOperand left(this, leftChild);
-    JSValueOperand right(this, rightChild);
</del><ins>+    JSValueOperand left(this, leftChild, ManualOperandSpeculation);
+    JSValueOperand right(this, rightChild, ManualOperandSpeculation);
+    speculate(node, leftChild);
+    speculate(node, rightChild);
</ins><span class="cx">     JSValueRegs leftRegs = left.jsValueRegs();
</span><span class="cx">     JSValueRegs rightRegs = right.jsValueRegs();
</span><span class="cx"> 
</span><span class="lines">@@ -6032,6 +6246,12 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+#if USE(BIGINT32)
+    if (node->isBinaryUseKind(BigInt32Use)) {
+        compileBigInt32Compare(node, condition);
+        return false;
+    }
+#endif
</ins><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">     if (node->isBinaryUseKind(Int52RepUse)) {
</span><span class="cx">         compileInt52Compare(node, condition);
</span><span class="lines">@@ -6060,6 +6280,9 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // FIXME: add HeapBigInt case here.
+    // Not having it means that the compare will not be fused with the branch for this case.
+
</ins><span class="cx">     if (node->op() == CompareEq) {
</span><span class="cx">         if (node->isBinaryUseKind(BooleanUse)) {
</span><span class="cx">             compileBooleanCompare(node, condition);
</span><span class="lines">@@ -6138,7 +6361,24 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-#if USE(JSVALUE64)   
</del><ins>+#if USE(BIGINT32)
+    if (node->isBinaryUseKind(BigInt32Use)) {
+        unsigned branchIndexInBlock = detectPeepHoleBranch();
+        if (branchIndexInBlock != UINT_MAX) {
+            Node* branchNode = m_block->at(branchIndexInBlock);
+            compilePeepHoleBigInt32Branch(node, branchNode, MacroAssembler::Equal);
+            use(node->child1());
+            use(node->child2());
+            m_indexInBlock = branchIndexInBlock;
+            m_currentNode = branchNode;
+            return true;
+        }
+        compileBigInt32Compare(node, MacroAssembler::Equal);
+        return false;
+    }
+#endif
+
+#if USE(JSVALUE64)
</ins><span class="cx">     if (node->isBinaryUseKind(Int52RepUse)) {
</span><span class="cx">         unsigned branchIndexInBlock = detectPeepHoleBranch();
</span><span class="cx">         if (branchIndexInBlock != UINT_MAX) {
</span><span class="lines">@@ -6185,8 +6425,8 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    if (node->isBinaryUseKind(BigIntUse)) {
-        compileBigIntEquality(node);
</del><ins>+    if (node->isBinaryUseKind(HeapBigIntUse)) {
+        compileHeapBigIntEquality(node);
</ins><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -6280,8 +6520,8 @@
</span><span class="cx">         compileStringToUntypedEquality(node, node->child2(), node->child1());
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><del>-    
-    RELEASE_ASSERT(node->isBinaryUseKind(UntypedUse));
</del><ins>+
+    ASSERT(node->isBinaryUseKind(UntypedUse) || node->isBinaryUseKind(AnyBigIntUse));
</ins><span class="cx">     return nonSpeculativeStrictEq(node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -10559,18 +10799,18 @@
</span><span class="cx">     speculateSymbol(edge, operand.gpr());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::speculateBigInt(Edge edge, GPRReg cell)
</del><ins>+void SpeculativeJIT::speculateHeapBigInt(Edge edge, GPRReg cell)
</ins><span class="cx"> {
</span><del>-    DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, ~SpecCellCheck | SpecBigInt, m_jit.branchIfNotBigInt(cell));
</del><ins>+    DFG_TYPE_CHECK(JSValueSource::unboxedCell(cell), edge, ~SpecCellCheck | SpecHeapBigInt, m_jit.branchIfNotHeapBigInt(cell));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::speculateBigInt(Edge edge)
</del><ins>+void SpeculativeJIT::speculateHeapBigInt(Edge edge)
</ins><span class="cx"> {
</span><span class="cx">     if (!needsTypeCheck(edge, SpecBigInt))
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     SpeculateCellOperand operand(this, edge);
</span><del>-    speculateBigInt(edge, operand.gpr());
</del><ins>+    speculateHeapBigInt(edge, operand.gpr());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::speculateNotCell(Edge edge, JSValueRegs regs)
</span><span class="lines">@@ -10740,9 +10980,17 @@
</span><span class="cx">     case SymbolUse:
</span><span class="cx">         speculateSymbol(edge);
</span><span class="cx">         break;
</span><del>-    case BigIntUse:
-        speculateBigInt(edge);
</del><ins>+#if USE(BIGINT32)
+    case BigInt32Use:
+        speculateBigInt32(edge);
</ins><span class="cx">         break;
</span><ins>+    case AnyBigIntUse:
+        speculateAnyBigInt(edge);
+        break;
+#endif
+    case HeapBigIntUse:
+        speculateHeapBigInt(edge);
+        break;
</ins><span class="cx">     case StringObjectUse:
</span><span class="cx">         speculateStringObject(edge);
</span><span class="cx">         break;
</span><span class="lines">@@ -13082,17 +13330,18 @@
</span><span class="cx">     JSValueRegs argumentRegs = argument.jsValueRegs();
</span><span class="cx">     JSValueRegs resultRegs = result.regs();
</span><span class="cx">     GPRReg scratch = temp.gpr();
</span><ins>+    // FIXME: add a fast path for BigInt32 here (and for typeOf, and for boolify or whatever it is called in this file).
</ins><span class="cx"> 
</span><span class="cx">     MacroAssembler::JumpList slowCases;
</span><span class="cx"> 
</span><span class="cx">     MacroAssembler::Jump notCell = m_jit.branchIfNotCell(argumentRegs);
</span><del>-    slowCases.append(m_jit.branchIfNotBigInt(argumentRegs.payloadGPR()));
-    MacroAssembler::Jump isBigInt = m_jit.jump();
</del><ins>+    slowCases.append(m_jit.branchIfNotHeapBigInt(argumentRegs.payloadGPR()));
+    MacroAssembler::Jump isHeapBigInt = m_jit.jump();
</ins><span class="cx"> 
</span><span class="cx">     notCell.link(&m_jit);
</span><span class="cx">     slowCases.append(m_jit.branchIfNotNumber(argumentRegs, scratch));
</span><span class="cx"> 
</span><del>-    isBigInt.link(&m_jit);
</del><ins>+    isHeapBigInt.link(&m_jit);
</ins><span class="cx">     m_jit.moveValueRegs(argumentRegs, resultRegs);
</span><span class="cx"> 
</span><span class="cx">     addSlowPathGenerator(slowPathCall(slowCases, this, operationToNumeric, resultRegs, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), argumentRegs));
</span><span class="lines">@@ -13981,9 +14230,9 @@
</span><span class="cx">     m_currentNode = branchNode;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeculativeJIT::compileBigIntEquality(Node* node)
</del><ins>+void SpeculativeJIT::compileHeapBigIntEquality(Node* node)
</ins><span class="cx"> {
</span><del>-    // FIXME: [ESNext][BigInt] Create specialized version of strict equals for BigIntUse
</del><ins>+    // FIXME: [ESNext][BigInt] Create specialized version of strict equals for big ints
</ins><span class="cx">     // https://bugs.webkit.org/show_bug.cgi?id=182895
</span><span class="cx">     SpeculateCellOperand left(this, node->child1());
</span><span class="cx">     SpeculateCellOperand right(this, node->child2());
</span><span class="lines">@@ -13995,8 +14244,8 @@
</span><span class="cx">     left.use();
</span><span class="cx">     right.use();
</span><span class="cx"> 
</span><del>-    speculateBigInt(node->child1(), leftGPR);
-    speculateBigInt(node->child2(), rightGPR);
</del><ins>+    speculateHeapBigInt(node->child1(), leftGPR);
+    speculateHeapBigInt(node->child2(), rightGPR);
</ins><span class="cx"> 
</span><span class="cx">     JITCompiler::Jump notEqualCase = m_jit.branchPtr(JITCompiler::NotEqual, leftGPR, rightGPR);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -346,6 +346,9 @@
</span><span class="cx">     FPRReg fillSpeculateDouble(Edge);
</span><span class="cx">     GPRReg fillSpeculateCell(Edge);
</span><span class="cx">     GPRReg fillSpeculateBoolean(Edge);
</span><ins>+#if USE(BIGINT32)
+    GPRReg fillSpeculateBigInt32(Edge);
+#endif
</ins><span class="cx">     GeneratedOperandType checkGeneratedTypeForToInt32(Node*);
</span><span class="cx"> 
</span><span class="cx">     void addSlowPathGenerator(std::unique_ptr<SlowPathGenerator>);
</span><span class="lines">@@ -1148,6 +1151,9 @@
</span><span class="cx">     bool compilePeepHoleBranch(Node*, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_JITOperation_GJJ);
</span><span class="cx">     void compilePeepHoleInt32Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
</span><span class="cx">     void compilePeepHoleInt52Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
</span><ins>+#if USE(BIGINT32)
+    void compilePeepHoleBigInt32Branch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
+#endif
</ins><span class="cx">     void compilePeepHoleBooleanBranch(Node*, Node* branchNode, JITCompiler::RelationalCondition);
</span><span class="cx">     void compilePeepHoleDoubleBranch(Node*, Node* branchNode, JITCompiler::DoubleCondition);
</span><span class="cx">     void compilePeepHoleObjectEquality(Node*, Node* branchNode);
</span><span class="lines">@@ -1172,7 +1178,7 @@
</span><span class="cx">     void compileMiscStrictEq(Node*);
</span><span class="cx"> 
</span><span class="cx">     void compileSymbolEquality(Node*);
</span><del>-    void compileBigIntEquality(Node*);
</del><ins>+    void compileHeapBigIntEquality(Node*);
</ins><span class="cx">     void compilePeepHoleSymbolEquality(Node*, Node* branchNode);
</span><span class="cx">     void compileSymbolUntypedEquality(Node*, Edge symbolEdge, Edge untypedEdge);
</span><span class="cx"> 
</span><span class="lines">@@ -1222,6 +1228,9 @@
</span><span class="cx">     
</span><span class="cx">     void compileInt32Compare(Node*, MacroAssembler::RelationalCondition);
</span><span class="cx">     void compileInt52Compare(Node*, MacroAssembler::RelationalCondition);
</span><ins>+#if USE(BIGINT32)
+    void compileBigInt32Compare(Node*, MacroAssembler::RelationalCondition);
+#endif
</ins><span class="cx">     void compileBooleanCompare(Node*, MacroAssembler::RelationalCondition);
</span><span class="cx">     void compileDoubleCompare(Node*, MacroAssembler::DoubleCondition);
</span><span class="cx">     void compileStringCompare(Node*, MacroAssembler::RelationalCondition);
</span><span class="lines">@@ -1297,11 +1306,11 @@
</span><span class="cx">     void compileBitwiseNot(Node*);
</span><span class="cx"> 
</span><span class="cx">     template<typename SnippetGenerator, J_JITOperation_GJJ slowPathFunction>
</span><del>-    void emitUntypedBitOp(Node*);
</del><ins>+    void emitUntypedOrAnyBigIntBitOp(Node*);
</ins><span class="cx">     void compileBitwiseOp(Node*);
</span><span class="cx">     void compileValueBitwiseOp(Node*);
</span><span class="cx"> 
</span><del>-    void emitUntypedRightShiftBitOp(Node*);
</del><ins>+    void emitUntypedOrBigIntRightShiftBitOp(Node*);
</ins><span class="cx">     void compileValueLShiftOp(Node*);
</span><span class="cx">     void compileValueBitRShift(Node*);
</span><span class="cx">     void compileShiftOp(Node*);
</span><span class="lines">@@ -1560,6 +1569,7 @@
</span><span class="cx">     // Helpers for performing type checks on an edge stored in the given registers.
</span><span class="cx">     bool needsTypeCheck(Edge edge, SpeculatedType typesPassedThrough) { return m_interpreter.needsTypeCheck(edge, typesPassedThrough); }
</span><span class="cx">     void typeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::Jump jumpToFail, ExitKind = BadType);
</span><ins>+    void typeCheck(JSValueSource, Edge, SpeculatedType typesPassedThrough, MacroAssembler::JumpList jumpListToFail, ExitKind = BadType);
</ins><span class="cx">     
</span><span class="cx">     void speculateCellTypeWithoutTypeFiltering(Edge, GPRReg cellGPR, JSType);
</span><span class="cx">     void speculateCellType(Edge, GPRReg cellGPR, SpeculatedType, JSType);
</span><span class="lines">@@ -1571,6 +1581,10 @@
</span><span class="cx">     void speculateInt32(Edge, JSValueRegs);
</span><span class="cx">     void speculateDoubleRepAnyInt(Edge);
</span><span class="cx"> #endif // USE(JSVALUE64)
</span><ins>+#if USE(BIGINT32)
+    void speculateBigInt32(Edge);
+    void speculateAnyBigInt(Edge);
+#endif // USE(BIGINT32)
</ins><span class="cx">     void speculateNumber(Edge);
</span><span class="cx">     void speculateRealNumber(Edge);
</span><span class="cx">     void speculateDoubleRepReal(Edge);
</span><span class="lines">@@ -1620,8 +1634,8 @@
</span><span class="cx">     void speculateStringOrStringObject(Edge);
</span><span class="cx">     void speculateSymbol(Edge, GPRReg cell);
</span><span class="cx">     void speculateSymbol(Edge);
</span><del>-    void speculateBigInt(Edge, GPRReg cell);
-    void speculateBigInt(Edge);
</del><ins>+    void speculateHeapBigInt(Edge, GPRReg cell);
+    void speculateHeapBigInt(Edge);
</ins><span class="cx">     void speculateNotCell(Edge, JSValueRegs);
</span><span class="cx">     void speculateNotCell(Edge);
</span><span class="cx">     void speculateOther(Edge, JSValueRegs, GPRReg temp);
</span><span class="lines">@@ -2599,6 +2613,56 @@
</span><span class="cx">     GPRReg m_gprOrInvalid;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+class SpeculateBigInt32Operand {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit SpeculateBigInt32Operand(SpeculativeJIT* jit, Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+        : m_jit(jit)
+        , m_edge(edge)
+        , m_gprOrInvalid(InvalidGPRReg)
+    {
+        ASSERT(m_jit);
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BigInt32Use);
+        if (jit->isFilled(node()))
+            gpr();
+    }
+
+    ~SpeculateBigInt32Operand()
+    {
+        ASSERT(m_gprOrInvalid != InvalidGPRReg);
+        m_jit->unlock(m_gprOrInvalid);
+    }
+
+    Edge edge() const
+    {
+        return m_edge;
+    }
+
+    Node* node() const
+    {
+        return edge().node();
+    }
+
+    GPRReg gpr()
+    {
+        if (m_gprOrInvalid == InvalidGPRReg)
+            m_gprOrInvalid = m_jit->fillSpeculateBigInt32(edge());
+        return m_gprOrInvalid;
+    }
+
+    void use()
+    {
+        m_jit->use(node());
+    }
+
+private:
+    SpeculativeJIT* m_jit;
+    Edge m_edge;
+    GPRReg m_gprOrInvalid;
+};
+#endif // USE(BIGINT32)
+
</ins><span class="cx"> #define DFG_TYPE_CHECK_WITH_EXIT_KIND(exitKind, source, edge, typesPassedThrough, jumpToFail) do { \
</span><span class="cx">         JSValueSource _dtc_source = (source);                           \
</span><span class="cx">         Edge _dtc_edge = (edge);                                        \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -4181,7 +4181,11 @@
</span><span class="cx">     case CheckArrayOrEmpty:
</span><span class="cx">         DFG_CRASH(m_jit.graph(), node, "CheckArrayOrEmpty only used in 64-bit DFG");
</span><span class="cx">         break;
</span><del>-        
</del><ins>+
+    case IsBigInt:
+        DFG_CRASH(m_jit.graph(), node, "IsBigInt is only used when USE_BIGINT32, which can only be true in 64 bit mode");
+        break;
+
</ins><span class="cx">     case FilterCallLinkStatus:
</span><span class="cx">     case FilterGetByStatus:
</span><span class="cx">     case FilterPutByIdStatus:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -138,7 +138,8 @@
</span><span class="cx">     case DataFormatJSInt32:
</span><span class="cx">     case DataFormatJSDouble:
</span><span class="cx">     case DataFormatJSCell:
</span><del>-    case DataFormatJSBoolean: {
</del><ins>+    case DataFormatJSBoolean:
+    case DataFormatJSBigInt32: {
</ins><span class="cx">         GPRReg gpr = info.gpr();
</span><span class="cx">         m_gprs.lock(gpr);
</span><span class="cx">         return gpr;
</span><span class="lines">@@ -340,8 +341,11 @@
</span><span class="cx">         notTaken = tmp;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    JSValueOperand arg1(this, node->child1());
-    JSValueOperand arg2(this, node->child2());
</del><ins>+    ASSERT(node->isBinaryUseKind(UntypedUse) || node->isBinaryUseKind(AnyBigIntUse));
+    JSValueOperand arg1(this, node->child1(), ManualOperandSpeculation);
+    JSValueOperand arg2(this, node->child2(), ManualOperandSpeculation);
+    speculate(node, node->child1());
+    speculate(node, node->child2());
</ins><span class="cx">     GPRReg arg1GPR = arg1.gpr();
</span><span class="cx">     GPRReg arg2GPR = arg2.gpr();
</span><span class="cx">     
</span><span class="lines">@@ -363,43 +367,67 @@
</span><span class="cx">         
</span><span class="cx">         branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultGPR, taken);
</span><span class="cx">     } else {
</span><del>-        m_jit.or64(arg1GPR, arg2GPR, resultGPR);
-        
-        JITCompiler::Jump twoCellsCase = m_jit.branchIfCell(resultGPR);
-        
-        JITCompiler::Jump leftOK = m_jit.branchIfInt32(arg1GPR);
-        JITCompiler::Jump leftDouble = m_jit.branchIfNumber(arg1GPR);
-        leftOK.link(&m_jit);
-        JITCompiler::Jump rightOK = m_jit.branchIfInt32(arg2GPR);
-        JITCompiler::Jump rightDouble = m_jit.branchIfNumber(arg2GPR);
-        rightOK.link(&m_jit);
-        
-        branch64(invert ? JITCompiler::NotEqual : JITCompiler::Equal, arg1GPR, arg2GPR, taken);
-        jump(notTaken, ForceJump);
-        
-        twoCellsCase.link(&m_jit);
</del><ins>+        /* At a high level we do (assuming 'invert' to be false):
+         If (left is Double || right is Double)
+            goto slowPath;
+         if (left == right)
+            goto taken;
+         if (left is Cell || right is Cell)
+            goto slowPath;
+         goto notTaken;
+         */
+
+        JITCompiler::JumpList slowPathCases;
+
+        // This fragment implements (left is Double || right is Double), with a single branch instead of the 4 that would be naively required if we used branchIfInt32/branchIfNumber
+        // The trick is that if a JSValue is an Int32, then adding 1<<49 to it will make it overflow, leaving all high bits at 0
+        // If it is not a number at all, then 1<<49 will be its only high bit set
+        // Leaving only doubles above or equal 1<<50.
+        GPRTemporary scratch(this);
+        m_jit.move(arg1GPR, resultGPR);
+        m_jit.move(arg2GPR, scratch.gpr());
+        m_jit.add64(TrustedImm64(JSValue::LowestOfHighBits), resultGPR);
+        m_jit.add64(TrustedImm64(JSValue::LowestOfHighBits), scratch.gpr());
+        m_jit.or64(scratch.gpr(), resultGPR, resultGPR);
+        constexpr uint64_t nextLowestOfHighBits = JSValue::LowestOfHighBits << 1;
+        slowPathCases.append(m_jit.branch64(JITCompiler::AboveOrEqual, resultGPR, TrustedImm64(nextLowestOfHighBits)));
+
</ins><span class="cx">         branch64(JITCompiler::Equal, arg1GPR, arg2GPR, invert ? notTaken : taken);
</span><span class="cx">         
</span><del>-        leftDouble.link(&m_jit);
-        rightDouble.link(&m_jit);
-        
-        silentSpillAllRegisters(resultGPR);
-        callOperation(operationCompareStrictEq, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR);
-        silentFillAllRegisters();
-        m_jit.exceptionCheck();
-        
</del><ins>+        // If we support BigInt32 we must go to a slow path if at least one operand is a cell (for HeapBigInt === BigInt32)
+        // If we don't support BigInt32, we only have to go to a slow path if both operands are cells (for HeapBigInt === HeapBigInt and String === String)
+        // Instead of doing two branches, we can do a single one, by observing that
+        // 1. (left is Cell && right is Cell) is the same as ((left | right) is Cell)
+        //      Both are "All high bits are 0"
+        // 2. Since we know that neither is a double, (left is Cell || right is Cell) is equivalent to ((left & right) is Cell)
+        //      If both are Int32, then the top bits will be set and the test will fail
+        //      If at least one is not Int32, then the top bits will be 0.
+        //      And if at least one is a cell, then the 'Other' tag will also be 0, making the test succeed
+#if USE(BIGINT32)
+        m_jit.and64(arg1GPR, arg2GPR, resultGPR);
+#else
+        m_jit.or64(arg1GPR, arg2GPR, resultGPR);
+#endif
+        slowPathCases.append(m_jit.branchIfCell(resultGPR));
+
+        jump(invert ? taken : notTaken, ForceJump);
+
+        addSlowPathGenerator(slowPathCall(slowPathCases, this, operationCompareStrictEq, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR));
</ins><span class="cx">         branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, resultGPR, taken);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     jump(notTaken);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::nonSpeculativeNonPeepholeStrictEq(Node* node, bool invert)
</span><span class="cx"> {
</span><ins>+    // FIXME: some of this code should be shareable with nonSpeculativePeepholeStrictEq
</ins><span class="cx">     JSValueOperand arg1(this, node->child1());
</span><span class="cx">     JSValueOperand arg2(this, node->child2());
</span><span class="cx">     JSValueRegs arg1Regs = arg1.jsValueRegs();
</span><span class="cx">     JSValueRegs arg2Regs = arg2.jsValueRegs();
</span><ins>+    GPRReg arg1GPR = arg1.gpr();
+    GPRReg arg2GPR = arg2.gpr();
</ins><span class="cx">     
</span><span class="cx">     GPRTemporary result(this);
</span><span class="cx">     GPRReg resultGPR = result.gpr();
</span><span class="lines">@@ -428,33 +456,60 @@
</span><span class="cx">         unblessedBooleanResult(resultGPR, m_currentNode, UseChildrenCalledExplicitly);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><ins>+    /* At a high level we do (assuming 'invert' to be false):
+    If (left is Double || right is Double)
+        goto slowPath;
+    result = (left == right);
+    if (result)
+        goto done;
+    if (left is Cell || right is Cell)
+        goto slowPath;
+    done:
+    return result;
+    */
</ins><span class="cx"> 
</span><del>-    m_jit.or64(arg1Regs.gpr(), arg2Regs.gpr(), resultGPR);
-
</del><span class="cx">     JITCompiler::JumpList slowPathCases;
</span><span class="cx"> 
</span><del>-    JITCompiler::Jump twoCellsCase = m_jit.branchIfCell(resultGPR);
</del><ins>+    // This fragment implements (left is Double || right is Double), with a single branch instead of the 4 that would be naively required if we used branchIfInt32/branchIfNumber
+    // The trick is that if a JSValue is an Int32, then adding 1<<49 to it will make it overflow, leaving all high bits at 0
+    // If it is not a number at all, then 1<<49 will be its only high bit set
+    // Leaving only doubles above or equal 1<<50.
+    GPRTemporary scratch(this);
+    m_jit.move(arg1GPR, resultGPR);
+    m_jit.move(arg2GPR, scratch.gpr());
+    m_jit.add64(TrustedImm64(JSValue::LowestOfHighBits), resultGPR);
+    m_jit.add64(TrustedImm64(JSValue::LowestOfHighBits), scratch.gpr());
+    m_jit.or64(scratch.gpr(), resultGPR, resultGPR);
+    constexpr uint64_t nextLowestOfHighBits = JSValue::LowestOfHighBits << 1;
+    slowPathCases.append(m_jit.branch64(JITCompiler::AboveOrEqual, resultGPR, TrustedImm64(nextLowestOfHighBits)));
</ins><span class="cx"> 
</span><del>-    JITCompiler::Jump leftOK = m_jit.branchIfInt32(arg1Regs);
-    slowPathCases.append(m_jit.branchIfNumber(arg1Regs, InvalidGPRReg));
-    leftOK.link(&m_jit);
-    JITCompiler::Jump rightOK = m_jit.branchIfInt32(arg2Regs);
-    slowPathCases.append(m_jit.branchIfNumber(arg2Regs, InvalidGPRReg));
-    rightOK.link(&m_jit);
</del><ins>+    m_jit.compare64(JITCompiler::Equal, arg1GPR, arg2GPR, resultGPR);
+    JITCompiler::Jump done = m_jit.branchTest64(JITCompiler::NonZero, resultGPR);
</ins><span class="cx"> 
</span><del>-    m_jit.compare64(invert ? JITCompiler::NotEqual : JITCompiler::Equal, arg1Regs.gpr(), arg2Regs.gpr(), resultGPR);
</del><ins>+    // If we support BigInt32 we must go to a slow path if at least one operand is a cell (for HeapBigInt === BigInt32)
+    // If we don't support BigInt32, we only have to go to a slow path if both operands are cells (for HeapBigInt === HeapBigInt and String === String)
+    // Instead of doing two branches, we can do a single one, by observing that
+    // 1. (left is Cell && right is Cell) is the same as ((left | right) is Cell)
+    //      Both are "All high bits are 0"
+    // 2. Since we know that neither is a double, (left is Cell || right is Cell) is equivalent to ((left & right) is Cell)
+    //      If both are Int32, then the top bits will be set and the test will fail
+    //      If at least one is not Int32, then the top bits will be 0.
+    //      And if at least one is a cell, then the 'Other' tag will also be 0, making the test succeed
+#if USE(BIGINT32)
+    m_jit.and64(arg1GPR, arg2GPR, resultGPR);
+#else
+    m_jit.or64(arg1GPR, arg2GPR, resultGPR);
+#endif
+    slowPathCases.append(m_jit.branchIfCell(resultGPR));
</ins><span class="cx"> 
</span><del>-    JITCompiler::Jump done = m_jit.jump();
</del><ins>+    m_jit.move(TrustedImm64(0), resultGPR);
</ins><span class="cx"> 
</span><del>-    twoCellsCase.link(&m_jit);
-    slowPathCases.append(m_jit.branch64(JITCompiler::NotEqual, arg1Regs.gpr(), arg2Regs.gpr()));
-
-    m_jit.move(JITCompiler::TrustedImm64(!invert), resultGPR);
-
</del><span class="cx">     addSlowPathGenerator(slowPathCall(slowPathCases, this, operationCompareStrictEq, resultGPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1Regs, arg2Regs));
</span><span class="cx"> 
</span><span class="cx">     done.link(&m_jit);
</span><span class="cx"> 
</span><ins>+    m_jit.xor64(TrustedImm64(invert), resultGPR);
+
</ins><span class="cx">     unblessedBooleanResult(resultGPR, m_currentNode, UseChildrenCalledExplicitly);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1004,6 +1059,8 @@
</span><span class="cx">     case DataFormatStorage:
</span><span class="cx">     case DataFormatInt52:
</span><span class="cx">     case DataFormatStrictInt52:
</span><ins>+    case DataFormatBigInt32:
+    case DataFormatJSBigInt32:
</ins><span class="cx">         DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
</span><span class="cx">         
</span><span class="cx">     default:
</span><span class="lines">@@ -1184,6 +1241,8 @@
</span><span class="cx">     GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
</span><span class="cx"> 
</span><span class="cx">     switch (info.registerFormat()) {
</span><ins>+    // FIXME: some of these cases look like they could share code.
+    // Look at fillSpeculateInt32Internal for an example.
</ins><span class="cx">     case DataFormatNone: {
</span><span class="cx">         GPRReg gpr = allocate();
</span><span class="cx"> 
</span><span class="lines">@@ -1235,6 +1294,8 @@
</span><span class="cx">     case DataFormatStorage:
</span><span class="cx">     case DataFormatInt52:
</span><span class="cx">     case DataFormatStrictInt52:
</span><ins>+    case DataFormatBigInt32:
+    case DataFormatJSBigInt32:
</ins><span class="cx">         DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
</span><span class="cx">         
</span><span class="cx">     default:
</span><span class="lines">@@ -1312,6 +1373,8 @@
</span><span class="cx">     case DataFormatStorage:
</span><span class="cx">     case DataFormatInt52:
</span><span class="cx">     case DataFormatStrictInt52:
</span><ins>+    case DataFormatBigInt32:
+    case DataFormatJSBigInt32:
</ins><span class="cx">         DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
</span><span class="cx">         
</span><span class="cx">     default:
</span><span class="lines">@@ -1320,6 +1383,126 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+void SpeculativeJIT::speculateBigInt32(Edge edge)
+{
+    if (!needsTypeCheck(edge, SpecBigInt32))
+        return;
+
+    (SpeculateBigInt32Operand(this, edge)).gpr();
+}
+
+void SpeculativeJIT::speculateAnyBigInt(Edge edge)
+{
+    if (!needsTypeCheck(edge, SpecBigInt))
+        return;
+
+    JSValueOperand value(this, edge, ManualOperandSpeculation);
+    JSValueRegs valueRegs = value.jsValueRegs();
+    GPRTemporary temp(this);
+    GPRReg tempGPR = temp.gpr();
+    JITCompiler::Jump notCell = m_jit.branchIfNotCell(valueRegs);
+    // I inlined speculateHeapBigInt because it would be incorrect to call it here if it did JSValueOperand / SpeculateXXXOperand,
+    // as it would confuse the DFG register allocator.
+    DFG_TYPE_CHECK(valueRegs, edge, ~SpecCellCheck | SpecHeapBigInt, m_jit.branchIfNotHeapBigInt(valueRegs.gpr()));
+    auto done = m_jit.jump();
+    notCell.link(&m_jit);
+    DFG_TYPE_CHECK(valueRegs, edge, SpecCellCheck | SpecBigInt32, m_jit.branchIfNotBigInt32(valueRegs.gpr(), tempGPR));
+    done.link(&m_jit);
+}
+
+GPRReg SpeculativeJIT::fillSpeculateBigInt32(Edge edge)
+{
+    AbstractValue& value = m_state.forNode(edge);
+    SpeculatedType type = value.m_type;
+
+    m_interpreter.filter(value, SpecBigInt32);
+    if (value.isClear()) {
+        if (mayHaveTypeCheck(edge.useKind()))
+            terminateSpeculativeExecution(Uncountable, JSValueRegs(), 0);
+        return allocate();
+    }
+
+    VirtualRegister virtualRegister = edge->virtualRegister();
+    GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
+
+    switch (info.registerFormat()) {
+    case DataFormatNone: {
+        GPRReg gpr = allocate();
+
+        if (edge->hasConstant()) {
+            JSValue jsValue = edge->asJSValue();
+            m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
+            ASSERT(jsValue.isBigInt32());
+            m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsValue)), gpr);
+            info.fillJSValue(*m_stream, gpr, DataFormatJSBigInt32);
+            return gpr;
+        }
+
+        DataFormat spillFormat = info.spillFormat();
+        DFG_ASSERT(m_jit.graph(), m_currentNode, (spillFormat & DataFormatJS) || spillFormat == DataFormatBigInt32, spillFormat);
+
+        m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+
+        if (spillFormat == DataFormatBigInt32) {
+            // We have not yet implemented this
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        if (spillFormat == DataFormatJSBigInt32) {
+            m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
+            info.fillJSValue(*m_stream, gpr, DataFormatJSBigInt32);
+            return gpr;
+        }
+
+        m_jit.load64(JITCompiler::addressFor(virtualRegister), gpr);
+
+        info.fillJSValue(*m_stream, gpr, DataFormatJS);
+        m_gprs.unlock(gpr);
+        FALLTHROUGH;
+    }
+
+    case DataFormatJS: {
+        GPRReg gpr = info.gpr();
+        m_gprs.lock(gpr);
+        if (type & ~SpecBigInt32) {
+            CCallHelpers::JumpList failureCases;
+            GPRReg tempGPR = allocate();
+            failureCases.append(m_jit.branchIfNumber(gpr));
+            failureCases.append(m_jit.branchIfNotBigInt32KnownNotNumber(gpr, tempGPR));
+            speculationCheck(BadType, JSValueRegs(gpr), edge, failureCases);
+            unlock(tempGPR);
+        }
+        info.fillJSValue(*m_stream, gpr, DataFormatJSBigInt32);
+        return gpr;
+    }
+
+    case DataFormatJSBigInt32: {
+        GPRReg gpr = info.gpr();
+        m_gprs.lock(gpr);
+        return gpr;
+    }
+
+    case DataFormatBoolean:
+    case DataFormatJSBoolean:
+    case DataFormatJSInt32:
+    case DataFormatInt32:
+    case DataFormatJSDouble:
+    case DataFormatJSCell:
+    case DataFormatCell:
+    case DataFormatDouble:
+    case DataFormatStorage:
+    case DataFormatInt52:
+    case DataFormatStrictInt52:
+    case DataFormatBigInt32:
+        DFG_CRASH(m_jit.graph(), m_currentNode, "Bad data format");
+
+    default:
+        DFG_CRASH(m_jit.graph(), m_currentNode, "Corrupt data format");
+        return InvalidGPRReg;
+    }
+}
+#endif // USE(BIGINT32)
+
</ins><span class="cx"> void SpeculativeJIT::compileObjectStrictEquality(Edge objectChild, Edge otherChild)
</span><span class="cx"> {
</span><span class="cx">     SpeculateCellOperand op1(this, objectChild);
</span><span class="lines">@@ -1556,6 +1739,61 @@
</span><span class="cx">     jump(notTaken);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+void SpeculativeJIT::compileBigInt32Compare(Node* node, MacroAssembler::RelationalCondition condition)
+{
+    SpeculateBigInt32Operand op1(this, node->child1());
+    SpeculateBigInt32Operand op2(this, node->child2());
+    GPRTemporary result(this, Reuse, op1, op2);
+
+    GPRReg op1GPR = op1.gpr();
+    GPRReg op2GPR = op2.gpr();
+    GPRReg resultGPR = result.gpr();
+
+    if (condition == MacroAssembler::Equal || condition == MacroAssembler::NotEqual) {
+        // No need to unbox the operands, since the tag bits are identical
+        m_jit.compare64(condition, op1.gpr(), op2.gpr(), result.gpr());
+    } else {
+        GPRTemporary temp(this);
+        GPRReg tempGPR = temp.gpr();
+
+        m_jit.move(op1GPR, tempGPR);
+        m_jit.unboxBigInt32(tempGPR);
+        m_jit.move(op2GPR, resultGPR);
+        m_jit.unboxBigInt32(resultGPR);
+        m_jit.compare64(condition, tempGPR, resultGPR, resultGPR);
+    }
+
+    // If we add a DataFormatBool, we should use it here.
+    m_jit.or32(TrustedImm32(JSValue::ValueFalse), result.gpr());
+    jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
+}
+
+void SpeculativeJIT::compilePeepHoleBigInt32Branch(Node* node, Node* branchNode, JITCompiler::RelationalCondition condition)
+{
+    // Other conditions would require unboxing the BigInt32 to get correct results on negative numbers.
+    ASSERT(condition == MacroAssembler::Equal || condition == MacroAssembler::NotEqual);
+
+    BasicBlock* taken = branchNode->branchData()->taken.block;
+    BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
+
+    // The branch instruction will branch to the taken block.
+    // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
+    if (taken == nextBlock()) {
+        condition = JITCompiler::invert(condition);
+        BasicBlock* tmp = taken;
+        taken = notTaken;
+        notTaken = tmp;
+    }
+
+    SpeculateBigInt32Operand op1(this, node->child1());
+    SpeculateBigInt32Operand op2(this, node->child2());
+
+    branch64(condition, op1.gpr(), op2.gpr(), taken);
+    jump(notTaken);
+}
+#endif // USE(BIGINT32)
+
</ins><span class="cx"> void SpeculativeJIT::compileCompareEqPtr(Node* node)
</span><span class="cx"> {
</span><span class="cx">     JSValueOperand value(this, node->child1());
</span><span class="lines">@@ -4082,6 +4320,31 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    case IsBigInt: {
+#if USE(BIGINT32)
+        JSValueOperand value(this, node->child1());
+        GPRTemporary result(this);
+        GPRReg resultGPR = result.gpr();
+
+        JITCompiler::Jump isCell = m_jit.branchIfCell(value.gpr());
+
+        m_jit.move(TrustedImm64(JSValue::BigInt32Mask), resultGPR);
+        m_jit.and64(value.gpr(), result.gpr());
+        m_jit.compare64(JITCompiler::Equal, resultGPR, TrustedImm32(JSValue::BigInt32Tag), resultGPR);
+        JITCompiler::Jump continuation = m_jit.jump();
+
+        isCell.link(&m_jit);
+        JSValueRegs valueRegs = value.jsValueRegs();
+        m_jit.compare8(JITCompiler::Equal, JITCompiler::Address(valueRegs.payloadGPR(), JSCell::typeInfoTypeOffset()), TrustedImm32(HeapBigIntType), resultGPR);
+
+        continuation.link(&m_jit);
+        unblessedBooleanResult(resultGPR, node);
+#else
+        RELEASE_ASSERT_NOT_REACHED();
+#endif
+        break;
+    }
+
</ins><span class="cx">     case NumberIsInteger: {
</span><span class="cx">         JSValueOperand value(this, node->child1());
</span><span class="cx">         GPRTemporary result(this, Reuse, value);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGStrengthReductionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -125,7 +125,8 @@
</span><span class="cx">         case ValueBitOr:
</span><span class="cx">         case ValueBitAnd:
</span><span class="cx">         case ValueBitXor: {
</span><del>-            if (m_node->binaryUseKind() == BigIntUse)
</del><ins>+            // FIXME: we should maybe support the case where one operand is always HeapBigInt and the other is always BigInt32?
+            if (m_node->binaryUseKind() == AnyBigIntUse || m_node->binaryUseKind() == BigInt32Use || m_node->binaryUseKind() == HeapBigIntUse)
</ins><span class="cx">                 handleCommutativity();
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="lines">@@ -375,7 +376,7 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            if (m_node->binaryUseKind() == BigIntUse)
</del><ins>+            if (m_node->binaryUseKind() == BigInt32Use || m_node->binaryUseKind() == HeapBigIntUse || m_node->binaryUseKind() == AnyBigIntUse)
</ins><span class="cx">                 handleCommutativity();
</span><span class="cx"> 
</span><span class="cx">             break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGUseKindcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGUseKind.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGUseKind.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGUseKind.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -145,9 +145,15 @@
</span><span class="cx">     case SymbolUse:
</span><span class="cx">         out.print("Symbol");
</span><span class="cx">         return;
</span><del>-    case BigIntUse:
-        out.print("BigInt");
</del><ins>+    case AnyBigIntUse:
+        out.print("AnyBigInt");
</ins><span class="cx">         return;
</span><ins>+    case HeapBigIntUse:
+        out.print("HeapBigInt");
+        return;
+    case BigInt32Use:
+        out.print("BigInt32");
+        return;
</ins><span class="cx">     case StringObjectUse:
</span><span class="cx">         out.print("StringObject");
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGUseKindh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGUseKind.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGUseKind.h     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/dfg/DFGUseKind.h        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -66,7 +66,9 @@
</span><span class="cx">     KnownStringUse,
</span><span class="cx">     KnownPrimitiveUse, // This bizarre type arises for op_strcat, which has a bytecode guarantee that it will only see primitives (i.e. not objects).
</span><span class="cx">     SymbolUse,
</span><del>-    BigIntUse,
</del><ins>+    AnyBigIntUse,
+    HeapBigIntUse,
+    BigInt32Use,
</ins><span class="cx">     DateObjectUse,
</span><span class="cx">     MapObjectUse,
</span><span class="cx">     SetObjectUse,
</span><span class="lines">@@ -152,8 +154,12 @@
</span><span class="cx">         return SpecHeapTop & ~SpecObject;
</span><span class="cx">     case SymbolUse:
</span><span class="cx">         return SpecSymbol;
</span><del>-    case BigIntUse:
</del><ins>+    case AnyBigIntUse:
</ins><span class="cx">         return SpecBigInt;
</span><ins>+    case HeapBigIntUse:
+        return SpecHeapBigInt;
+    case BigInt32Use:
+        return SpecBigInt32;
</ins><span class="cx">     case PromiseObjectUse:
</span><span class="cx">         return SpecPromiseObject;
</span><span class="cx">     case DateObjectUse:
</span><span class="lines">@@ -212,24 +218,6 @@
</span><span class="cx">     return !shouldNotHaveTypeCheck(kind);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline bool isNumerical(UseKind kind)
-{
-    switch (kind) {
-    case Int32Use:
-    case KnownInt32Use:
-    case NumberUse:
-    case RealNumberUse:
-    case Int52RepUse:
-    case DoubleRepUse:
-    case DoubleRepRealUse:
-    case AnyIntUse:
-    case DoubleRepAnyIntUse:
-        return true;
-    default:
-        return false;
-    }
-}
-
</del><span class="cx"> inline bool isDouble(UseKind kind)
</span><span class="cx"> {
</span><span class="cx">     switch (kind) {
</span><span class="lines">@@ -261,7 +249,7 @@
</span><span class="cx">     case StringUse:
</span><span class="cx">     case KnownStringUse:
</span><span class="cx">     case SymbolUse:
</span><del>-    case BigIntUse:
</del><ins>+    case HeapBigIntUse:
</ins><span class="cx">     case StringObjectUse:
</span><span class="cx">     case StringOrStringObjectUse:
</span><span class="cx">     case DateObjectUse:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -260,6 +260,7 @@
</span><span class="cx">     case IsUndefinedOrNull:
</span><span class="cx">     case IsBoolean:
</span><span class="cx">     case IsNumber:
</span><ins>+    case IsBigInt:
</ins><span class="cx">     case NumberIsInteger:
</span><span class="cx">     case IsObject:
</span><span class="cx">     case IsObjectOrNull:
</span><span class="lines">@@ -483,7 +484,9 @@
</span><span class="cx">                 case StringObjectUse:
</span><span class="cx">                 case StringOrStringObjectUse:
</span><span class="cx">                 case SymbolUse:
</span><del>-                case BigIntUse:
</del><ins>+                case AnyBigIntUse:
+                case BigInt32Use:
+                case HeapBigIntUse:
</ins><span class="cx">                 case DateObjectUse:
</span><span class="cx">                 case MapObjectUse:
</span><span class="cx">                 case SetObjectUse:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCommonValuescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCommonValues.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCommonValues.cpp      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/ftl/FTLCommonValues.cpp 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -58,6 +58,9 @@
</span><span class="cx">     intPtrThree = block->appendNew<ConstPtrValue>(proc, Origin(), 3);
</span><span class="cx">     intPtrEight = block->appendNew<ConstPtrValue>(proc, Origin(), 8);
</span><span class="cx">     doubleZero = block->appendNew<ConstDoubleValue>(proc, Origin(), 0.);
</span><ins>+#if USE(BIGINT32)
+    bigInt32Zero = block->appendNew<Const64Value>(proc, Origin(), JSValue::BigInt32Tag);
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::FTL
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCommonValuesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCommonValues.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCommonValues.h        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/ftl/FTLCommonValues.h   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -56,7 +56,10 @@
</span><span class="cx">     LValue intPtrThree { nullptr };
</span><span class="cx">     LValue intPtrEight { nullptr };
</span><span class="cx">     LValue doubleZero { nullptr };
</span><del>-    
</del><ins>+#if USE(BIGINT32)
+    LValue bigInt32Zero { nullptr };
+#endif
+
</ins><span class="cx">     const unsigned rangeKind { 0 };
</span><span class="cx">     const unsigned profKind { 0 };
</span><span class="cx">     const LValue branchWeights { nullptr };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1356,6 +1356,9 @@
</span><span class="cx">         case IsNumber:
</span><span class="cx">             compileIsNumber();
</span><span class="cx">             break;
</span><ins>+        case IsBigInt:
+            compileIsBigInt();
+            break;
</ins><span class="cx">         case NumberIsInteger:
</span><span class="cx">             compileNumberIsInteger();
</span><span class="cx">             break;
</span><span class="lines">@@ -2139,11 +2142,28 @@
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><span class="cx"> 
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><ins>+#if USE(BIGINT32)
+        if (m_node->isBinaryUseKind(BigInt32Use)) {
+            LValue left = lowBigInt32(m_node->child1());
+            LValue right = lowBigInt32(m_node->child2());
</ins><span class="cx"> 
</span><del>-            LValue result = vmCall(pointerType(), operationAddBigInt, weakPointer(globalObject), left, right);
</del><ins>+            LValue unboxedLeft = unboxBigInt32(left);
+            LValue unboxedRight = unboxBigInt32(right);
+
+            CheckValue* result = m_out.speculateAdd(unboxedLeft, unboxedRight);
+            blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
+
+            LValue boxedResult = boxBigInt32(result);
+            setJSValue(boxedResult);
+            return;
+        }
+#endif
+
+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
+
+            LValue result = vmCall(pointerType(), operationAddHeapBigInt, weakPointer(globalObject), left, right);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -2160,11 +2180,28 @@
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><span class="cx"> 
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><ins>+#if USE(BIGINT32)
+        if (m_node->isBinaryUseKind(BigInt32Use)) {
+            LValue left = lowBigInt32(m_node->child1());
+            LValue right = lowBigInt32(m_node->child2());
+
+            LValue unboxedLeft = unboxBigInt32(left);
+            LValue unboxedRight = unboxBigInt32(right);
+
+            CheckValue* result = m_out.speculateSub(unboxedLeft, unboxedRight);
+            blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
+
+            LValue boxedResult = boxBigInt32(result);
+            setJSValue(boxedResult);
+            return;
+        }
+#endif
+
+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
</ins><span class="cx">             
</span><del>-            LValue result = vmCall(pointerType(), operationSubBigInt, weakPointer(globalObject), left, right);
</del><ins>+            LValue result = vmCall(pointerType(), operationSubHeapBigInt, weakPointer(globalObject), left, right);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -2181,11 +2218,28 @@
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><span class="cx"> 
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><ins>+#if USE(BIGINT32)
+        if (m_node->isBinaryUseKind(BigInt32Use)) {
+            LValue left = lowBigInt32(m_node->child1());
+            LValue right = lowBigInt32(m_node->child2());
+
+            LValue unboxedLeft = unboxBigInt32(left);
+            LValue unboxedRight = unboxBigInt32(right);
+
+            CheckValue* result = m_out.speculateMul(unboxedLeft, unboxedRight);
+            blessSpeculation(result, Overflow, noValue(), nullptr, m_origin);
+
+            LValue boxedResult = boxBigInt32(result);
+            setJSValue(boxedResult);
+            return;
+        }
+#endif
+
+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
</ins><span class="cx">             
</span><del>-            LValue result = vmCall(Int64, operationMulBigInt, weakPointer(globalObject), left, right);
</del><ins>+            LValue result = vmCall(Int64, operationMulHeapBigInt, weakPointer(globalObject), left, right);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -2289,7 +2343,21 @@
</span><span class="cx">     void compileBinaryMathIC(BinaryArithProfile* arithProfile, Func1 repatchingFunction, Func2 nonRepatchingFunction)
</span><span class="cx">     {
</span><span class="cx">         Node* node = m_node;
</span><del>-        
</del><ins>+
+#if USE(BIGINT32)
+        if (node->isBinaryUseKind(AnyBigIntUse)) {
+            // FIXME: This is not supported by the IC yet.
+            LValue left = lowJSValue(node->child1(), ManualOperandSpeculation);
+            LValue right = lowJSValue(node->child2(), ManualOperandSpeculation);
+            speculate(node, node->child1());
+            speculate(node, node->child2());
+
+            JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
+            setJSValue(vmCall(pointerType(), nonRepatchingFunction, weakPointer(globalObject), left, right));
+            return;
+        }
+#endif
+
</ins><span class="cx">         LValue left = lowJSValue(node->child1());
</span><span class="cx">         LValue right = lowJSValue(node->child2());
</span><span class="cx"> 
</span><span class="lines">@@ -2558,11 +2626,12 @@
</span><span class="cx">     void compileValueDiv()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><ins>+        // FIXME: add a fast path for BigInt32 here
+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
</ins><span class="cx">             
</span><del>-            LValue result = vmCall(pointerType(), operationDivBigInt, weakPointer(globalObject), left, right);
</del><ins>+            LValue result = vmCall(pointerType(), operationDivHeapBigInt, weakPointer(globalObject), left, right);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -2637,18 +2706,21 @@
</span><span class="cx">     void compileValueMod()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>-        if (m_node->binaryUseKind() == BigIntUse) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><ins>+        // FIXME: add a BigInt32 fast path here
+        if (m_node->binaryUseKind() == HeapBigIntUse) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
</ins><span class="cx"> 
</span><del>-            LValue result = vmCall(pointerType(), operationModBigInt, weakPointer(globalObject), left, right);
</del><ins>+            LValue result = vmCall(pointerType(), operationModHeapBigInt, weakPointer(globalObject), left, right);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        DFG_ASSERT(m_graph, m_node, m_node->binaryUseKind() == UntypedUse, m_node->binaryUseKind());
-        LValue left = lowJSValue(m_node->child1());
-        LValue right = lowJSValue(m_node->child2());
</del><ins>+        DFG_ASSERT(m_graph, m_node, m_node->binaryUseKind() == UntypedUse || m_node->binaryUseKind() == AnyBigIntUse, m_node->binaryUseKind());
+        LValue left = lowJSValue(m_node->child1(), ManualOperandSpeculation);
+        LValue right = lowJSValue(m_node->child2(), ManualOperandSpeculation);
+        speculate(m_node, m_node->child1());
+        speculate(m_node, m_node->child2());
</ins><span class="cx">         LValue result = vmCall(Int64, operationValueMod, weakPointer(globalObject), left, right);
</span><span class="cx">         setJSValue(result);
</span><span class="cx">     }
</span><span class="lines">@@ -2813,17 +2885,21 @@
</span><span class="cx">     void compileValuePow()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue base = lowBigInt(m_node->child1());
-            LValue exponent = lowBigInt(m_node->child2());
</del><ins>+        // FIXME: maybe add a fast path for BigInt32 here
+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue base = lowHeapBigInt(m_node->child1());
+            LValue exponent = lowHeapBigInt(m_node->child2());
</ins><span class="cx">             
</span><del>-            LValue result = vmCall(pointerType(), operationPowBigInt, weakPointer(globalObject), base, exponent);
</del><ins>+            LValue result = vmCall(pointerType(), operationPowHeapBigInt, weakPointer(globalObject), base, exponent);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        LValue base = lowJSValue(m_node->child1());
-        LValue exponent = lowJSValue(m_node->child2());
</del><ins>+        ASSERT(m_node->isBinaryUseKind(UntypedUse) || m_node->isBinaryUseKind(AnyBigIntUse));
+        LValue base = lowJSValue(m_node->child1(), ManualOperandSpeculation);
+        LValue exponent = lowJSValue(m_node->child2(), ManualOperandSpeculation);
+        speculate(m_node, m_node->child1());
+        speculate(m_node, m_node->child2());
</ins><span class="cx">         LValue result = vmCall(Int64, operationValuePow, weakPointer(globalObject), base, exponent);
</span><span class="cx">         setJSValue(result);
</span><span class="cx">     }
</span><span class="lines">@@ -3204,13 +3280,27 @@
</span><span class="cx">     void compileValueBitNot()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>-        if (m_node->child1().useKind() == BigIntUse) {
-            LValue operand = lowBigInt(m_node->child1());
-            LValue result = vmCall(pointerType(), operationBitNotBigInt, weakPointer(globalObject), operand);
</del><ins>+
+#if USE(BIGINT32)
+        if (m_node->child1().useKind() == BigInt32Use) {
+            LValue operand = lowBigInt32(m_node->child1());
+            // The following trick relies on details of the representation of BigInt32, and will have to be updated if we move bits around.
+            static_assert(JSValue::BigInt32Tag == 0x12);
+            static_assert(JSValue::BigInt32Mask == 0xfffe000000000012);
+            uint64_t maskForBigInt32Bits = 0x0000ffffffff0000;
+            LValue result = m_out.bitXor(operand, m_out.constInt64(maskForBigInt32Bits));
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+#endif
</ins><span class="cx"> 
</span><ins>+        if (m_node->child1().useKind() == HeapBigIntUse) {
+            LValue operand = lowHeapBigInt(m_node->child1());
+            LValue result = vmCall(pointerType(), operationBitNotHeapBigInt, weakPointer(globalObject), operand);
+            setJSValue(result);
+            return;
+        }
+
</ins><span class="cx">         LValue operand = lowJSValue(m_node->child1());
</span><span class="cx">         LValue result = vmCall(Int64, operationValueBitNot, weakPointer(globalObject), operand);
</span><span class="cx">         setJSValue(result);
</span><span class="lines">@@ -3224,11 +3314,23 @@
</span><span class="cx">     void compileValueBitAnd()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><ins>+
+#if USE(BIGINT32)
+        if (m_node->isBinaryUseKind(BigInt32Use)) {
+            LValue left = lowBigInt32(m_node->child1());
+            LValue right = lowBigInt32(m_node->child2());
+            // No need to unbox, since the tagging is not affected by bitAnd
+            LValue result = m_out.bitAnd(left, right);
+            setJSValue(result);
+            return;
+        }
+#endif
+
+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
</ins><span class="cx">             
</span><del>-            LValue result = vmCall(pointerType(), operationBitAndBigInt, weakPointer(globalObject), left, right);
</del><ins>+            LValue result = vmCall(pointerType(), operationBitAndHeapBigInt, weakPointer(globalObject), left, right);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -3244,15 +3346,27 @@
</span><span class="cx">     void compileValueBitOr()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><span class="cx"> 
</span><del>-            LValue result = vmCall(pointerType(), operationBitOrBigInt, weakPointer(globalObject), left, right);
</del><ins>+#if USE(BIGINT32)
+        if (m_node->isBinaryUseKind(BigInt32Use)) {
+            LValue left = lowBigInt32(m_node->child1());
+            LValue right = lowBigInt32(m_node->child2());
+            // No need to unbox, since the tagging is not affected by bitAnd
+            LValue result = m_out.bitOr(left, right);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+#endif
</ins><span class="cx"> 
</span><ins>+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
+
+            LValue result = vmCall(pointerType(), operationBitOrHeapBigInt, weakPointer(globalObject), left, right);
+            setJSValue(result);
+            return;
+        }
+
</ins><span class="cx">         emitBinaryBitOpSnippet<JITBitOrGenerator>(operationValueBitOr);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -3264,15 +3378,27 @@
</span><span class="cx">     void compileValueBitXor()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><span class="cx"> 
</span><del>-            LValue result = vmCall(pointerType(), operationBitXorBigInt, weakPointer(globalObject), left, right);
</del><ins>+#if USE(BIGINT32)
+        if (m_node->isBinaryUseKind(BigInt32Use)) {
+            LValue left = lowBigInt32(m_node->child1());
+            LValue right = lowBigInt32(m_node->child2());
+            LValue resultMissingTag = m_out.bitXor(left, right);
+            LValue result = m_out.bitOr(resultMissingTag, m_out.constInt64(JSValue::BigInt32Tag));
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+#endif
</ins><span class="cx"> 
</span><ins>+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
+
+            LValue result = vmCall(pointerType(), operationBitXorHeapBigInt, weakPointer(globalObject), left, right);
+            setJSValue(result);
+            return;
+        }
+
</ins><span class="cx">         emitBinaryBitOpSnippet<JITBitXorGenerator>(operationValueBitXor);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -3284,15 +3410,33 @@
</span><span class="cx">     void compileValueBitRShift()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><span class="cx"> 
</span><del>-            LValue result = vmCall(pointerType(), operationBitRShiftBigInt, weakPointer(globalObject), left, right);
</del><ins>+#if USE(BIGINT32)
+        if (m_node->isBinaryUseKind(AnyBigIntUse) || m_node->isBinaryUseKind(BigInt32Use)) {
+            // FIXME: do something smarter here
+            // Things are a bit tricky because a right-shift by a negative number is a left-shift for BigInts.
+            // So even a right shift can overflow.
+
+            LValue left = lowJSValue(m_node->child1(), ManualOperandSpeculation);
+            LValue right = lowJSValue(m_node->child2(), ManualOperandSpeculation);
+            speculate(m_node, m_node->child1());
+            speculate(m_node, m_node->child2());
+
+            LValue result = vmCall(pointerType(), operationValueBitRShift, weakPointer(globalObject), left, right);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+#endif // USE(BIGINT32)
</ins><span class="cx"> 
</span><ins>+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
+
+            LValue result = vmCall(pointerType(), operationBitRShiftHeapBigInt, weakPointer(globalObject), left, right);
+            setJSValue(result);
+            return;
+        }
+
</ins><span class="cx">         emitRightShiftSnippet(JITRightShiftGenerator::SignedShift);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -3300,7 +3444,7 @@
</span><span class="cx">     {
</span><span class="cx">         setInt32(m_out.aShr(
</span><span class="cx">             lowInt32(m_node->child1()),
</span><del>-            m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
</del><ins>+            m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31)))); // FIXME: I don't think that the BitAnd is useful, it is included in the semantics of shift in B3
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compileArithBitLShift()
</span><span class="lines">@@ -3307,17 +3451,18 @@
</span><span class="cx">     {
</span><span class="cx">         setInt32(m_out.shl(
</span><span class="cx">             lowInt32(m_node->child1()),
</span><del>-            m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
</del><ins>+            m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31)))); // FIXME: I don't think that the BitAnd is useful, it is included in the semantics of shift in B3
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compileValueBitLShift()
</span><span class="cx">     {
</span><span class="cx">         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><ins>+        // FIXME: consider adding a fast path for BigInt32 here.
+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
</ins><span class="cx">             
</span><del>-            LValue result = vmCall(pointerType(), operationBitLShiftBigInt, weakPointer(globalObject), left, right);
</del><ins>+            LValue result = vmCall(pointerType(), operationBitLShiftHeapBigInt, weakPointer(globalObject), left, right);
</ins><span class="cx">             setJSValue(result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -3334,7 +3479,7 @@
</span><span class="cx">         }
</span><span class="cx">         setInt32(m_out.lShr(
</span><span class="cx">             lowInt32(m_node->child1()),
</span><del>-            m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31))));
</del><ins>+            m_out.bitAnd(lowInt32(m_node->child2()), m_out.constInt32(31)))); // FIXME: I don't think that the BitAnd is useful, it is included in the semantics of shift in B3
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compileUInt32ToNumber()
</span><span class="lines">@@ -7384,6 +7529,9 @@
</span><span class="cx">         
</span><span class="cx">         if (abstractValue(m_node->child1()).m_type & (SpecBytecodeNumber | SpecBigInt)) {
</span><span class="cx">             LBasicBlock notNumber = m_out.newBlock();
</span><ins>+#if USE(BIGINT32)
+            LBasicBlock notBigInt32 = m_out.newBlock();
+#endif
</ins><span class="cx">             LBasicBlock isCellPath = m_out.newBlock();
</span><span class="cx">             LBasicBlock slowPath = m_out.newBlock();
</span><span class="cx">             LBasicBlock continuation = m_out.newBlock();
</span><span class="lines">@@ -7393,10 +7541,14 @@
</span><span class="cx"> 
</span><span class="cx">             // notNumber case.
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(notNumber, continuation);
</span><ins>+#if USE(BIGINT32)
+            m_out.branch(isBigInt32(value, provenType(m_node->child1())), unsure(continuation), unsure(notBigInt32));
+            m_out.appendTo(notBigInt32);
+#endif
</ins><span class="cx">             m_out.branch(isCell(value, provenType(m_node->child1())), unsure(isCellPath), unsure(slowPath));
</span><span class="cx"> 
</span><span class="cx">             m_out.appendTo(isCellPath);
</span><del>-            m_out.branch(isBigInt(value, provenType(m_node->child1())), unsure(continuation), unsure(slowPath));
</del><ins>+            m_out.branch(isHeapBigInt(value, provenType(m_node->child1())), unsure(continuation), unsure(slowPath));
</ins><span class="cx">             
</span><span class="cx">             m_out.appendTo(slowPath);
</span><span class="cx">             // We have several attempts to remove ToNumeric. But ToNumeric still exists.
</span><span class="lines">@@ -8466,7 +8618,10 @@
</span><span class="cx">             || m_node->isBinaryUseKind(BooleanUse)
</span><span class="cx">             || m_node->isBinaryUseKind(SymbolUse)
</span><span class="cx">             || m_node->isBinaryUseKind(StringIdentUse)
</span><del>-            || m_node->isBinaryUseKind(StringUse)) {
</del><ins>+            || m_node->isBinaryUseKind(StringUse)
+            || m_node->isBinaryUseKind(BigInt32Use)
+            || m_node->isBinaryUseKind(HeapBigIntUse)
+            || m_node->isBinaryUseKind(AnyBigIntUse)) {
</ins><span class="cx">             compileCompareStrictEq();
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -8509,7 +8664,105 @@
</span><span class="cx">                 m_out.equal(lowInt32(m_node->child1()), lowInt32(m_node->child2())));
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        
</del><ins>+
+#if USE(BIGINT32)
+        if (m_node->isBinaryUseKind(BigInt32Use)) {
+            LValue left = lowBigInt32(m_node->child1());
+            LValue right = lowBigInt32(m_node->child2());
+
+            // No need to unbox since the tag bits are the same on both sides
+            LValue result = m_out.equal(left, right);
+            setBoolean(result);
+            return;
+        }
+
+        if (m_node->isBinaryUseKind(AnyBigIntUse)) {
+            LValue left = lowJSValue(m_node->child1(), ManualOperandSpeculation);
+            LValue right = lowJSValue(m_node->child2(), ManualOperandSpeculation);
+
+            // Note that we cannot start with if (left == right), because we must insert the right checks (see ManualOperandSpeculation above)
+            // The code that we generate looks like the following pseudo-code:
+            /*
+             if (isBigInt32(left)) {
+                if (isBigInt32(right))
+                    return left == right;
+                CHECK(isHeapBigInt(right));
+                return call(JSBigInt::equalsToInt32(right, unboxed(left));
+             }
+             CHECK(isHeapBigInt(left))
+             if (left == right)
+                return true;
+             if (isBigInt32(right))
+                return call(JSBigInt::equalsToInt32(left, unboxed(right));
+             CHECK(isHeapBigInt(right));
+             return call(JSBigInt::equals(left, right));
+            */
+            LBasicBlock leftIsBigInt32 = m_out.newBlock();
+            LBasicBlock bothAreBigInt32 = m_out.newBlock();
+            LBasicBlock onlyLeftIsBigInt32 = m_out.newBlock();
+            LBasicBlock leftIsNotBigInt32 = m_out.newBlock();
+            LBasicBlock leftEqualsRight = m_out.newBlock();
+            LBasicBlock leftIsHeapBigInt = m_out.newBlock();
+            LBasicBlock rightIsBigInt32 = m_out.newBlock();
+            LBasicBlock rightIsNotBigInt32 = m_out.newBlock();
+            LBasicBlock continuation = m_out.newBlock();
+
+            // Inserts a check that a value is a HeapBigInt, assuming only that we know it is not a BigInt32
+            auto checkIsHeapBigInt = [&](LValue lowValue, Edge highValue) {
+                if (m_interpreter.needsTypeCheck(highValue, SpecHeapBigInt)) {
+                    ASSERT(mayHaveTypeCheck(highValue.useKind()));
+                    LValue checkFailed = isNotHeapBigIntUnknownWhetherCell(lowValue, ~SpecBigInt32);
+                    appendOSRExit(BadType, jsValueValue(lowValue), highValue.node(), checkFailed, m_origin);
+                }
+            };
+
+            m_out.branch(isBigInt32(left, provenType(m_node->child1())), unsure(leftIsBigInt32), unsure(leftIsNotBigInt32));
+
+            LBasicBlock lastNext = m_out.appendTo(leftIsBigInt32, bothAreBigInt32);
+            m_out.branch(isBigInt32(right, provenType(m_node->child2())), unsure(bothAreBigInt32), unsure(onlyLeftIsBigInt32));
+
+            m_out.appendTo(bothAreBigInt32, onlyLeftIsBigInt32);
+            ValueFromBlock resultBothAreBigInt32 = m_out.anchor(m_out.equal(left, right));
+            m_out.jump(continuation);
+
+            m_out.appendTo(onlyLeftIsBigInt32, leftIsNotBigInt32);
+            checkIsHeapBigInt(right, m_node->child2());
+            LValue unboxedLeft = unboxBigInt32(left);
+            ValueFromBlock resultLeftIsBigInt32 = m_out.anchor(m_out.notNull(vmCall(pointerType(), operationCompareEqHeapBigIntToInt32, weakPointer(globalObject), right, unboxedLeft)));
+            m_out.jump(continuation);
+
+            m_out.appendTo(leftIsNotBigInt32, leftEqualsRight);
+            checkIsHeapBigInt(left, m_node->child1());
+            m_out.branch(m_out.equal(left, right), unsure(leftEqualsRight), unsure(leftIsHeapBigInt));
+
+            m_out.appendTo(leftEqualsRight, leftIsHeapBigInt);
+            ValueFromBlock resultLeftEqualsRight = m_out.anchor(m_out.booleanTrue);
+            m_out.jump(continuation);
+
+            m_out.appendTo(leftIsHeapBigInt, rightIsBigInt32);
+            m_out.branch(isBigInt32(right, provenType(m_node->child2())), unsure(rightIsBigInt32), unsure(rightIsNotBigInt32));
+
+            m_out.appendTo(rightIsBigInt32, rightIsNotBigInt32);
+            LValue unboxedRight = unboxBigInt32(right);
+            ValueFromBlock resultRightIsBigInt32 = m_out.anchor(m_out.notNull(vmCall(pointerType(), operationCompareEqHeapBigIntToInt32, weakPointer(globalObject), left, unboxedRight)));
+            m_out.jump(continuation);
+
+            m_out.appendTo(rightIsNotBigInt32, continuation);
+            checkIsHeapBigInt(right, m_node->child2());
+            // FIXME: [ESNext][BigInt] Create specialized version of strict equals for big ints
+            // https://bugs.webkit.org/show_bug.cgi?id=182895
+            ValueFromBlock resultBothHeapBigInt = m_out.anchor(m_out.notNull(vmCall(pointerType(), operationCompareStrictEq, weakPointer(globalObject), left, right)));
+            m_out.jump(continuation);
+
+            m_out.appendTo(continuation, lastNext);
+            setBoolean(m_out.phi(Int32, resultBothAreBigInt32, resultLeftIsBigInt32, resultLeftEqualsRight, resultRightIsBigInt32, resultBothHeapBigInt));
+
+            m_interpreter.filter(m_node->child1(), SpecBigInt);
+            m_interpreter.filter(m_node->child2(), SpecBigInt);
+            return;
+        }
+#endif // USE(BIGINT32)
+
</ins><span class="cx">         if (m_node->isBinaryUseKind(Int52RepUse)) {
</span><span class="cx">             Int52Kind kind;
</span><span class="cx">             LValue left = lowWhicheverInt52(m_node->child1(), kind);
</span><span class="lines">@@ -8592,11 +8845,11 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        if (m_node->isBinaryUseKind(BigIntUse)) {
-            // FIXME: [ESNext][BigInt] Create specialized version of strict equals for BigIntUse
</del><ins>+        if (m_node->isBinaryUseKind(HeapBigIntUse)) {
+            // FIXME: [ESNext][BigInt] Create specialized version of strict equals for big ints
</ins><span class="cx">             // https://bugs.webkit.org/show_bug.cgi?id=182895
</span><del>-            LValue left = lowBigInt(m_node->child1());
-            LValue right = lowBigInt(m_node->child2());
</del><ins>+            LValue left = lowHeapBigInt(m_node->child1());
+            LValue right = lowHeapBigInt(m_node->child2());
</ins><span class="cx"> 
</span><span class="cx">             LBasicBlock notTriviallyEqualCase = m_out.newBlock();
</span><span class="cx">             LBasicBlock continuation = m_out.newBlock();
</span><span class="lines">@@ -8682,6 +8935,7 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        // FIXME: we can do something much smarter here, see the DFGSpeculativeJIT approach in e.g. SpeculativeJIT::nonSpeculativePeepholeStrictEq
</ins><span class="cx">         DFG_ASSERT(m_graph, m_node, m_node->isBinaryUseKind(UntypedUse), m_node->child1().useKind(), m_node->child2().useKind());
</span><span class="cx">         nonSpeculativeCompare(
</span><span class="cx">             [&] (LValue left, LValue right) {
</span><span class="lines">@@ -10645,7 +10899,37 @@
</span><span class="cx">         m_out.appendTo(continuation, lastNext);
</span><span class="cx">         setBoolean(m_out.phi(Int32, trueResult, falseResult, patchpointResult));
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+#if USE(BIGINT32)
+    void compileIsBigInt()
+    {
+        LValue value = lowJSValue(m_node->child1());
+
+        LBasicBlock isCellCase = m_out.newBlock();
+        LBasicBlock isNotCellCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        m_out.branch(isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(isNotCellCase));
+
+        LBasicBlock lastNext = m_out.appendTo(isNotCellCase, isCellCase);
+        // FIXME: we should filter the provenType to include the fact that we know we are not dealing with a cell
+        ValueFromBlock notCellResult = m_out.anchor(isBigInt32(value, provenType(m_node->child1())));
+        m_out.jump(continuation);
+
+        m_out.appendTo(isCellCase, continuation);
+        ValueFromBlock cellResult = m_out.anchor(isCellWithType(value, m_node->queriedType(), m_node->speculatedTypeForQuery(), provenType(m_node->child1())));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setBoolean(m_out.phi(Int32, notCellResult, cellResult));
+    }
+#else // if !USE(BIGINT32)
+    NO_RETURN_DUE_TO_CRASH ALWAYS_INLINE void compileIsBigInt()
+    {
+        // If we are not dealing with BigInt32, we should just emit IsCellWithType(HeapBigInt) instead.
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+#endif
</ins><span class="cx">     void compileIsCellWithType()
</span><span class="cx">     {
</span><span class="cx">         if (m_node->child1().useKind() == UntypedUse) {
</span><span class="lines">@@ -14383,10 +14667,12 @@
</span><span class="cx">     void emitBinarySnippet(J_JITOperation_GJJ slowPathFunction)
</span><span class="cx">     {
</span><span class="cx">         Node* node = m_node;
</span><del>-        
-        LValue left = lowJSValue(node->child1());
-        LValue right = lowJSValue(node->child2());
</del><span class="cx"> 
</span><ins>+        LValue left = lowJSValue(node->child1(), ManualOperandSpeculation);
+        LValue right = lowJSValue(node->child2(), ManualOperandSpeculation);
+        speculate(node->child1());
+        speculate(node->child2());
+
</ins><span class="cx">         SnippetOperand leftOperand(m_state.forNode(node->child1()).resultType());
</span><span class="cx">         SnippetOperand rightOperand(m_state.forNode(node->child2()).resultType());
</span><span class="cx">             
</span><span class="lines">@@ -14451,8 +14737,11 @@
</span><span class="cx">     {
</span><span class="cx">         Node* node = m_node;
</span><span class="cx">         
</span><del>-        LValue left = lowJSValue(node->child1());
-        LValue right = lowJSValue(node->child2());
</del><ins>+        ASSERT(node->isBinaryUseKind(UntypedUse) || node->isBinaryUseKind(AnyBigIntUse));
+        LValue left = lowJSValue(node->child1(), ManualOperandSpeculation);
+        LValue right = lowJSValue(node->child2(), ManualOperandSpeculation);
+        speculate(node, node->child1());
+        speculate(node, node->child2());
</ins><span class="cx"> 
</span><span class="cx">         SnippetOperand leftOperand(m_state.forNode(node->child1()).resultType());
</span><span class="cx">         SnippetOperand rightOperand(m_state.forNode(node->child2()).resultType());
</span><span class="lines">@@ -15064,7 +15353,7 @@
</span><span class="cx">             
</span><span class="cx">             // Implements the following control flow structure:
</span><span class="cx">             // if (value is cell) {
</span><del>-            //     if (value is string or value is BigInt)
</del><ins>+            //     if (value is string or value is HeapBigInt)
</ins><span class="cx">             //         result = !!value->length
</span><span class="cx">             //     else {
</span><span class="cx">             //         do evil things for masquerades-as-undefined
</span><span class="lines">@@ -15074,6 +15363,8 @@
</span><span class="cx">             //     result = !!unboxInt32(value)
</span><span class="cx">             // } else if (value is number) {
</span><span class="cx">             //     result = !!unboxDouble(value)
</span><ins>+            // } else if (value is BigInt32) {
+            //     result = (value != BigInt32Tag)
</ins><span class="cx">             // } else {
</span><span class="cx">             //     result = value == jsTrue
</span><span class="cx">             // }
</span><span class="lines">@@ -15081,13 +15372,17 @@
</span><span class="cx">             LBasicBlock cellCase = m_out.newBlock();
</span><span class="cx">             LBasicBlock notStringCase = m_out.newBlock();
</span><span class="cx">             LBasicBlock stringCase = m_out.newBlock();
</span><del>-            LBasicBlock bigIntCase = m_out.newBlock();
-            LBasicBlock notStringOrBigIntCase = m_out.newBlock();
</del><ins>+            LBasicBlock heapBigIntCase = m_out.newBlock();
+            LBasicBlock notStringNorHeapBigIntCase = m_out.newBlock();
</ins><span class="cx">             LBasicBlock notCellCase = m_out.newBlock();
</span><span class="cx">             LBasicBlock int32Case = m_out.newBlock();
</span><span class="cx">             LBasicBlock notInt32Case = m_out.newBlock();
</span><span class="cx">             LBasicBlock doubleCase = m_out.newBlock();
</span><span class="cx">             LBasicBlock notDoubleCase = m_out.newBlock();
</span><ins>+#if USE(BIGINT32)
+            LBasicBlock bigInt32Case = m_out.newBlock();
+            LBasicBlock notBigInt32Case = m_out.newBlock();
+#endif
</ins><span class="cx">             LBasicBlock continuation = m_out.newBlock();
</span><span class="cx">             
</span><span class="cx">             Vector<ValueFromBlock> results;
</span><span class="lines">@@ -15101,20 +15396,20 @@
</span><span class="cx">             
</span><span class="cx">             m_out.appendTo(notStringCase, stringCase);
</span><span class="cx">             m_out.branch(
</span><del>-                isBigInt(value, provenType(edge) & (SpecCell - SpecString)),
-                unsure(bigIntCase), unsure(notStringOrBigIntCase));
</del><ins>+                isHeapBigInt(value, provenType(edge) & (SpecCell - SpecString)),
+                unsure(heapBigIntCase), unsure(notStringNorHeapBigIntCase));
</ins><span class="cx"> 
</span><del>-            m_out.appendTo(stringCase, bigIntCase);
</del><ins>+            m_out.appendTo(stringCase, heapBigIntCase);
</ins><span class="cx">             results.append(m_out.anchor(m_out.notEqual(value, weakPointer(jsEmptyString(m_graph.m_vm)))));
</span><span class="cx">             m_out.jump(continuation);
</span><span class="cx"> 
</span><del>-            m_out.appendTo(bigIntCase, notStringOrBigIntCase);
</del><ins>+            m_out.appendTo(heapBigIntCase, notStringNorHeapBigIntCase);
</ins><span class="cx">             LValue nonZeroBigInt = m_out.notZero32(
</span><span class="cx">                 m_out.load32NonNegative(value, m_heaps.JSBigInt_length));
</span><span class="cx">             results.append(m_out.anchor(nonZeroBigInt));
</span><span class="cx">             m_out.jump(continuation);
</span><span class="cx">             
</span><del>-            m_out.appendTo(notStringOrBigIntCase, notCellCase);
</del><ins>+            m_out.appendTo(notStringNorHeapBigIntCase, notCellCase);
</ins><span class="cx">             LValue isTruthyObject;
</span><span class="cx">             if (masqueradesAsUndefinedWatchpointIsStillValid())
</span><span class="cx">                 isTruthyObject = m_out.booleanTrue;
</span><span class="lines">@@ -15157,8 +15452,22 @@
</span><span class="cx">                 unboxDouble(value), m_out.constDouble(0));
</span><span class="cx">             results.append(m_out.anchor(doubleIsTruthy));
</span><span class="cx">             m_out.jump(continuation);
</span><ins>+
+#if USE(BIGINT32)
+            m_out.appendTo(notDoubleCase, bigInt32Case);
+            m_out.branch(
+                isBigInt32(value, provenType(edge) & ~SpecCell),
+                unsure(bigInt32Case), unsure(notBigInt32Case));
+
+            m_out.appendTo(bigInt32Case, notBigInt32Case);
+            LValue bigInt32NotZero = m_out.notEqual(value, m_out.constInt64(JSValue::BigInt32Tag));
+            results.append(m_out.anchor(bigInt32NotZero));
+            m_out.jump(continuation);
</ins><span class="cx">             
</span><ins>+            m_out.appendTo(notBigInt32Case, continuation);
+#else
</ins><span class="cx">             m_out.appendTo(notDoubleCase, continuation);
</span><ins>+#endif
</ins><span class="cx">             LValue miscIsTruthy = m_out.equal(
</span><span class="cx">                 value, m_out.constInt64(JSValue::encode(jsBoolean(true))));
</span><span class="cx">             results.append(m_out.anchor(miscIsTruthy));
</span><span class="lines">@@ -15763,7 +16072,7 @@
</span><span class="cx">         //         }
</span><span class="cx">         //     } else if (is string) {
</span><span class="cx">         //         return string
</span><del>-        //     } else if (is bigint) {
</del><ins>+        //     } else if (is heapbigint) {
</ins><span class="cx">         //         return bigint
</span><span class="cx">         //     } else {
</span><span class="cx">         //         return symbol
</span><span class="lines">@@ -15770,6 +16079,8 @@
</span><span class="cx">         //     }
</span><span class="cx">         // } else if (is number) {
</span><span class="cx">         //     return number
</span><ins>+        // } else if (is bigint32) {
+        //     return bigint
</ins><span class="cx">         // } else if (is null) {
</span><span class="cx">         //     return object
</span><span class="cx">         // } else if (is boolean) {
</span><span class="lines">@@ -15797,6 +16108,9 @@
</span><span class="cx">         LBasicBlock notCellCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock numberCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock notNumberCase = m_out.newBlock();
</span><ins>+#if USE(BIGINT32)
+        LBasicBlock notBigInt32Case = m_out.newBlock();
+#endif
</ins><span class="cx">         LBasicBlock notNullCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock booleanCase = m_out.newBlock();
</span><span class="cx">         LBasicBlock undefinedCase = m_out.newBlock();
</span><span class="lines">@@ -15849,7 +16163,7 @@
</span><span class="cx"> 
</span><span class="cx">         m_out.appendTo(notStringCase, bigIntCase);
</span><span class="cx">         m_out.branch(
</span><del>-            isBigInt(value, provenType(child) & (SpecCell - SpecObject - SpecString)),
</del><ins>+            isHeapBigInt(value, provenType(child) & (SpecCell - SpecObject - SpecString)),
</ins><span class="cx">             unsure(bigIntCase), unsure(symbolCase));
</span><span class="cx"> 
</span><span class="cx">         m_out.appendTo(bigIntCase, symbolCase);
</span><span class="lines">@@ -15865,8 +16179,15 @@
</span><span class="cx">         
</span><span class="cx">         m_out.appendTo(numberCase, notNumberCase);
</span><span class="cx">         functor(TypeofType::Number);
</span><del>-        
</del><ins>+
+#if USE(BIGINT32)
+        m_out.appendTo(notNumberCase, notBigInt32Case);
+        m_out.branch(isBigInt32(value, provenType(child) & ~SpecCell), unsure(bigIntCase), unsure(notBigInt32Case));
+
+        m_out.appendTo(notBigInt32Case, notNullCase);
+#else
</ins><span class="cx">         m_out.appendTo(notNumberCase, notNullCase);
</span><ins>+#endif
</ins><span class="cx">         LValue isNull;
</span><span class="cx">         if (provenType(child) & SpecOther)
</span><span class="cx">             isNull = m_out.equal(value, m_out.constInt64(JSValue::ValueNull));
</span><span class="lines">@@ -16564,15 +16885,33 @@
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LValue lowBigInt(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
</del><ins>+    LValue lowHeapBigInt(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
</ins><span class="cx">     {
</span><del>-        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BigIntUse);
</del><ins>+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == HeapBigIntUse);
</ins><span class="cx"> 
</span><span class="cx">         LValue result = lowCell(edge, mode);
</span><del>-        speculateBigInt(edge, result);
</del><ins>+        speculateHeapBigInt(edge, result);
</ins><span class="cx">         return result;
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+#if USE(BIGINT32)
+    LValue lowBigInt32(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+    {
+        ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == BigInt32Use);
+
+        LoweredNodeValue value = m_jsValueValues.get(edge.node());
+        if (isValid(value)) {
+            LValue result = value.value();
+            FTL_TYPE_CHECK(jsValueValue(result), edge, SpecBigInt32, isNotBigInt32(result));
+            return result;
+        }
+
+        if (mayHaveTypeCheck(edge.useKind()))
+            terminate(Uncountable);
+        return m_out.bigInt32Zero;
+    }
+#endif
+
</ins><span class="cx">     LValue lowNonNullObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
</span><span class="cx">     {
</span><span class="cx">         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
</span><span class="lines">@@ -16758,7 +17097,73 @@
</span><span class="cx">     {
</span><span class="cx">         return m_out.add(m_out.zeroExt(value, Int64), m_numberTag);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+#if USE(BIGINT32)
+    LValue isBigInt32(LValue jsValue, SpeculatedType type = SpecFullTop)
+    {
+        if (LValue proven = isProvenValue(type, SpecBigInt32))
+            return proven;
+        return m_out.equal(
+            m_out.bitAnd(jsValue, m_out.constInt64(JSValue::BigInt32Mask)),
+            m_out.constInt64(JSValue::BigInt32Tag));
+    }
+    LValue isNotBigInt32(LValue jsValue, SpeculatedType type = SpecFullTop)
+    {
+        if (LValue proven = isProvenValue(type, ~SpecBigInt32))
+            return proven;
+        return m_out.notEqual(
+            m_out.bitAnd(jsValue, m_out.constInt64(JSValue::BigInt32Mask)),
+            m_out.constInt64(JSValue::BigInt32Tag));
+    }
+    LValue unboxBigInt32(LValue jsValue)
+    {
+        return m_out.castToInt32(m_out.lShr(jsValue, m_out.constInt64(16)));
+    }
+    LValue boxBigInt32(LValue int32Value)
+    {
+        return m_out.bitOr(
+            m_out.shl(m_out.zeroExt(int32Value, B3::Int64), m_out.constInt64(16)),
+            m_out.constInt64(JSValue::BigInt32Tag));
+    }
+    LValue isNotAnyBigInt(LValue jsValue, SpeculatedType type = SpecFullTop)
+    {
+        if (LValue proven = isProvenValue(type, ~SpecBigInt))
+            return proven;
+
+        // if (isBigInt32)
+        //   return false
+        // if (!isCell)
+        //   return true;
+        // return !isHeapBigInt
+        LBasicBlock isBigInt32Case = m_out.newBlock();
+        LBasicBlock isNotBigInt32Case = m_out.newBlock();
+        LBasicBlock isNotCellCase = m_out.newBlock();
+        LBasicBlock isCellCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        m_out.branch(isBigInt32(jsValue, type), unsure(isBigInt32Case), unsure(isNotBigInt32Case));
+
+        LBasicBlock lastNext = m_out.appendTo(isBigInt32Case, isNotBigInt32Case);
+        ValueFromBlock returnFalse = m_out.anchor(m_out.booleanFalse);
+        m_out.jump(continuation);
+
+        m_out.appendTo(isNotBigInt32Case, isNotCellCase);
+        // FIXME: we should filter the type passed to isCell to account for the previous test that told us we are definitely not a BigInt32.
+        m_out.branch(isCell(jsValue, type), unsure(isCellCase), unsure(isNotCellCase));
+
+        m_out.appendTo(isNotCellCase, isCellCase);
+        ValueFromBlock returnTrue = m_out.anchor(m_out.booleanTrue);
+        m_out.jump(continuation);
+
+        m_out.appendTo(isCellCase, continuation);
+        ValueFromBlock returnIsNotHeapBigInt = m_out.anchor(isNotHeapBigInt(jsValue));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        return m_out.phi(Int32, returnFalse, returnTrue, returnIsNotHeapBigInt);
+    }
+#endif // USE(BIGINT32)
+
</ins><span class="cx">     LValue isCellOrMisc(LValue jsValue, SpeculatedType type = SpecFullTop)
</span><span class="cx">     {
</span><span class="cx">         if (LValue proven = isProvenValue(type, SpecCellCheck | SpecMisc))
</span><span class="lines">@@ -17070,9 +17475,17 @@
</span><span class="cx">         case BooleanUse:
</span><span class="cx">             speculateBoolean(edge);
</span><span class="cx">             break;
</span><del>-        case BigIntUse:
-            speculateBigInt(edge);
</del><ins>+#if USE(BIGINT32)
+        case BigInt32Use:
+            speculateBigInt32(edge);
</ins><span class="cx">             break;
</span><ins>+        case AnyBigIntUse:
+            speculateAnyBigInt(edge);
+            break;
+#endif // USE(BIGINT32)
+        case HeapBigIntUse:
+            speculateHeapBigInt(edge);
+            break;
</ins><span class="cx">         case NotStringVarUse:
</span><span class="cx">             speculateNotStringVar(edge);
</span><span class="cx">             break;
</span><span class="lines">@@ -17257,18 +17670,38 @@
</span><span class="cx">             m_out.constInt32(vm().symbolStructure->id()));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LValue isNotBigInt(LValue cell, SpeculatedType type = SpecFullTop)
</del><ins>+    LValue isNotHeapBigIntUnknownWhetherCell(LValue value, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><del>-        if (LValue proven = isProvenValue(type & SpecCell, ~SpecBigInt))
</del><ins>+        if (LValue proven = isProvenValue(type, ~SpecHeapBigInt))
</ins><span class="cx">             return proven;
</span><ins>+
+        LBasicBlock isCellCase = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        ValueFromBlock defaultToFalse = m_out.anchor(m_out.booleanFalse);
+        m_out.branch(isCell(value, type), unsure(isCellCase), unsure(continuation));
+
+        LBasicBlock lastNext = m_out.appendTo(isCellCase, continuation);
+        ValueFromBlock returnForCell = m_out.anchor(isHeapBigInt(value, type));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        LValue result = m_out.phi(Int32, defaultToFalse, returnForCell);
+        return result;
+    }
+
+    LValue isNotHeapBigInt(LValue cell, SpeculatedType type = SpecFullTop)
+    {
+        if (LValue proven = isProvenValue(type & SpecCell, ~SpecHeapBigInt))
+            return proven;
</ins><span class="cx">         return m_out.notEqual(
</span><span class="cx">             m_out.load32(cell, m_heaps.JSCell_structureID),
</span><span class="cx">             m_out.constInt32(vm().bigIntStructure->id()));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    LValue isBigInt(LValue cell, SpeculatedType type = SpecFullTop)
</del><ins>+    LValue isHeapBigInt(LValue cell, SpeculatedType type = SpecFullTop)
</ins><span class="cx">     {
</span><del>-        if (LValue proven = isProvenValue(type & SpecCell, SpecBigInt))
</del><ins>+        if (LValue proven = isProvenValue(type & SpecCell, SpecHeapBigInt))
</ins><span class="cx">             return proven;
</span><span class="cx">         return m_out.equal(
</span><span class="cx">             m_out.load32(cell, m_heaps.JSCell_structureID),
</span><span class="lines">@@ -17726,16 +18159,29 @@
</span><span class="cx">         speculateSymbol(edge, lowCell(edge));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void speculateBigInt(Edge edge, LValue cell)
</del><ins>+    void speculateHeapBigInt(Edge edge, LValue cell)
</ins><span class="cx">     {
</span><del>-        FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecBigInt, isNotBigInt(cell));
</del><ins>+        FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecHeapBigInt, isNotHeapBigInt(cell));
</ins><span class="cx">     }
</span><ins>+    void speculateHeapBigInt(Edge edge)
+    {
+        speculateHeapBigInt(edge, lowCell(edge));
+    }
</ins><span class="cx"> 
</span><del>-    void speculateBigInt(Edge edge)
</del><ins>+#if USE(BIGINT32)
+    void speculateBigInt32(Edge edge)
</ins><span class="cx">     {
</span><del>-        speculateBigInt(edge, lowCell(edge));
</del><ins>+        LValue value = lowJSValue(edge, ManualOperandSpeculation);
+        FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBigInt32, isNotBigInt32(value));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void speculateAnyBigInt(Edge edge)
+    {
+        LValue value = lowJSValue(edge, ManualOperandSpeculation);
+        FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBigInt, isNotAnyBigInt(value));
+    }
+#endif
+
</ins><span class="cx">     void speculateNonNullObject(Edge edge, LValue cell)
</span><span class="cx">     {
</span><span class="cx">         FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecObject, isNotObject(cell));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOSRExitCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExitCompiler.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -282,7 +282,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (exit.m_descriptor->m_valueProfile)
</span><del>-            exit.m_descriptor->m_valueProfile.emitReportValue(jit, JSValueRegs(GPRInfo::regT0));
</del><ins>+            exit.m_descriptor->m_valueProfile.emitReportValue(jit, JSValueRegs(GPRInfo::regT0), GPRInfo::regT1);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Materialize all objects. Don't materialize an object until all
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapSnapshotBuildercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp 2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp    2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -422,7 +422,7 @@
</span><span class="cx"> 
</span><span class="cx">         void* wrappedAddress = 0;
</span><span class="cx">         unsigned labelIndex = 0;
</span><del>-        if (!node.cell->isString() && !node.cell->isBigInt()) {
</del><ins>+        if (!node.cell->isString() && !node.cell->isHeapBigInt()) {
</ins><span class="cx">             Structure* structure = node.cell->structure(vm);
</span><span class="cx">             if (!structure || !structure->globalObject())
</span><span class="cx">                 flags |= static_cast<unsigned>(NodeFlags::Internal);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMarkedBlockInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/MarkedBlockInlines.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MarkedBlockInlines.h    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/heap/MarkedBlockInlines.h       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -29,7 +29,7 @@
</span><span class="cx"> #include "JSCast.h"
</span><span class="cx"> #include "MarkedBlock.h"
</span><span class="cx"> #include "MarkedSpace.h"
</span><del>-#include "Operations.h"
</del><ins>+#include "Scribble.h"
</ins><span class="cx"> #include "SuperSampler.h"
</span><span class="cx"> #include "VM.h"
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapPreciseAllocationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/PreciseAllocation.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/PreciseAllocation.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/heap/PreciseAllocation.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx"> #include "Heap.h"
</span><span class="cx"> #include "IsoCellSetInlines.h"
</span><span class="cx"> #include "JSCInlines.h"
</span><del>-#include "Operations.h"
</del><ins>+#include "Scribble.h"
</ins><span class="cx"> #include "SubspaceInlines.h"
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectoragentsInspectorHeapAgentcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/inspector/agents/InspectorHeapAgent.cpp 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -187,8 +187,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // BigInt preview.
</span><del>-    if (cell->isBigInt()) {
-        resultString = JSBigInt::tryGetString(vm, asBigInt(cell), 10);
</del><ins>+    if (cell->isHeapBigInt()) {
+        resultString = JSBigInt::tryGetString(vm, asHeapBigInt(cell), 10);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -205,7 +205,7 @@
</span><span class="cx">         break;
</span><span class="cx">     case StringType:
</span><span class="cx">     case SymbolType:
</span><del>-    case BigIntType:
</del><ins>+    case HeapBigIntType:
</ins><span class="cx">         throwException(globalObject, scope, createInvalidFunctionApplyParameterError(globalObject,  arguments));
</span><span class="cx">         return 0;
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelperscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -688,7 +688,7 @@
</span><span class="cx"> {
</span><span class="cx">     // Implements the following control flow structure:
</span><span class="cx">     // if (value is cell) {
</span><del>-    //     if (value is string or value is BigInt)
</del><ins>+    //     if (value is string or value is HeapBigInt)
</ins><span class="cx">     //         result = !!value->length
</span><span class="cx">     //     else {
</span><span class="cx">     //         do evil things for masquerades-as-undefined
</span><span class="lines">@@ -698,6 +698,8 @@
</span><span class="cx">     //     result = !!unboxInt32(value)
</span><span class="cx">     // } else if (value is number) {
</span><span class="cx">     //     result = !!unboxDouble(value)
</span><ins>+    // } else if (value is BigInt32) {
+    //     result = !!unboxBigInt32(value)
</ins><span class="cx">     // } else {
</span><span class="cx">     //     result = value == jsTrue
</span><span class="cx">     // }
</span><span class="lines">@@ -706,7 +708,7 @@
</span><span class="cx"> 
</span><span class="cx">     auto notCell = branchIfNotCell(value);
</span><span class="cx">     auto isString = branchIfString(value.payloadGPR());
</span><del>-    auto isBigInt = branchIfBigInt(value.payloadGPR());
</del><ins>+    auto isHeapBigInt = branchIfHeapBigInt(value.payloadGPR());
</ins><span class="cx"> 
</span><span class="cx">     if (shouldCheckMasqueradesAsUndefined) {
</span><span class="cx">         ASSERT(scratchIfShouldCheckMasqueradesAsUndefined != InvalidGPRReg);
</span><span class="lines">@@ -729,7 +731,7 @@
</span><span class="cx">     comparePtr(invert ? Equal : NotEqual, value.payloadGPR(), result, result);
</span><span class="cx">     done.append(jump());
</span><span class="cx"> 
</span><del>-    isBigInt.link(this);
</del><ins>+    isHeapBigInt.link(this);
</ins><span class="cx">     load32(Address(value.payloadGPR(), JSBigInt::offsetOfLength()), result);
</span><span class="cx">     compare32(invert ? Equal : NotEqual, result, TrustedImm32(0), result);
</span><span class="cx">     done.append(jump());
</span><span class="lines">@@ -752,6 +754,15 @@
</span><span class="cx">     done.append(jump());
</span><span class="cx"> 
</span><span class="cx">     notDouble.link(this);
</span><ins>+#if USE(BIGINT32)
+    auto isNotBigInt32 = branchIfNotBigInt32KnownNotNumber(value.gpr(), result);
+    move(value.gpr(), result);
+    urshift64(TrustedImm32(16), result);
+    compare32(invert ? Equal : NotEqual, result, TrustedImm32(0), result);
+    done.append(jump());
+
+    isNotBigInt32.link(this);
+#endif // USE(BIGINT32)
</ins><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">     compare64(invert ? NotEqual : Equal, value.gpr(), TrustedImm32(JSValue::ValueTrue), result);
</span><span class="cx"> #else
</span><span class="lines">@@ -767,7 +778,7 @@
</span><span class="cx"> {
</span><span class="cx">     // Implements the following control flow structure:
</span><span class="cx">     // if (value is cell) {
</span><del>-    //     if (value is string or value is BigInt)
</del><ins>+    //     if (value is string or value is HeapBigInt)
</ins><span class="cx">     //         result = !!value->length
</span><span class="cx">     //     else {
</span><span class="cx">     //         do evil things for masquerades-as-undefined
</span><span class="lines">@@ -777,6 +788,8 @@
</span><span class="cx">     //     result = !!unboxInt32(value)
</span><span class="cx">     // } else if (value is number) {
</span><span class="cx">     //     result = !!unboxDouble(value)
</span><ins>+    // } else if (value is BigInt32) {
+    //     result = !!unboxBigInt32(value)
</ins><span class="cx">     // } else {
</span><span class="cx">     //     result = value == jsTrue
</span><span class="cx">     // }
</span><span class="lines">@@ -786,7 +799,7 @@
</span><span class="cx"> 
</span><span class="cx">     auto notCell = branchIfNotCell(value);
</span><span class="cx">     auto isString = branchIfString(value.payloadGPR());
</span><del>-    auto isBigInt = branchIfBigInt(value.payloadGPR());
</del><ins>+    auto isHeapBigInt = branchIfHeapBigInt(value.payloadGPR());
</ins><span class="cx"> 
</span><span class="cx">     if (shouldCheckMasqueradesAsUndefined) {
</span><span class="cx">         ASSERT(scratchIfShouldCheckMasqueradesAsUndefined != InvalidGPRReg);
</span><span class="lines">@@ -817,7 +830,7 @@
</span><span class="cx">     truthy.append(branchPtr(invert ? Equal : NotEqual, value.payloadGPR(), TrustedImmPtr(jsEmptyString(vm))));
</span><span class="cx">     done.append(jump());
</span><span class="cx"> 
</span><del>-    isBigInt.link(this);
</del><ins>+    isHeapBigInt.link(this);
</ins><span class="cx">     truthy.append(branchTest32(invert ? Zero : NonZero, Address(value.payloadGPR(), JSBigInt::offsetOfLength())));
</span><span class="cx">     done.append(jump());
</span><span class="cx"> 
</span><span class="lines">@@ -842,6 +855,15 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     notDouble.link(this);
</span><ins>+#if USE(BIGINT32)
+    auto isNotBigInt32 = branchIfNotBigInt32KnownNotNumber(value.gpr(), scratch);
+    move(value.gpr(), scratch);
+    urshift64(TrustedImm32(16), scratch);
+    truthy.append(branchTest32(invert ? Zero : NonZero, scratch));
+    done.append(jump());
+
+    isNotBigInt32.link(this);
+#endif // USE(BIGINT32)
</ins><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">     truthy.append(branch64(invert ? NotEqual : Equal, value.gpr(), TrustedImm64(JSValue::encode(jsBoolean(true)))));
</span><span class="cx"> #else
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -929,7 +929,46 @@
</span><span class="cx">         return branchIfNotBoolean(regs.tagGPR(), tempGPR);
</span><span class="cx"> #endif
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+#if USE(BIGINT32)
+    Jump branchIfBigInt32(GPRReg gpr, GPRReg tempGPR, TagRegistersMode mode = HaveTagRegisters)
+    {
+        Jump number = branchIfNumber(gpr, mode);
+        Jump bigInt32 = branchIfBigInt32KnownNotNumber(gpr, tempGPR);
+        number.link(this);
+        return bigInt32;
+    }
+    JumpList branchIfNotBigInt32(GPRReg gpr, GPRReg tempGPR, TagRegistersMode mode = HaveTagRegisters)
+    {
+        JumpList result;
+        result.append(branchIfNumber(gpr, mode));
+        Jump bigInt32 = branchIfBigInt32KnownNotNumber(gpr, tempGPR);
+        result.append(jump());
+        bigInt32.link(this);
+        return result;
+    }
+
+    Jump branchIfBigInt32KnownNotNumber(GPRReg gpr, GPRReg tempGPR)
+    {
+        ASSERT(tempGPR != InvalidGPRReg);
+        move(gpr, tempGPR);
+        and64(TrustedImm32(JSValue::BigInt32Tag), tempGPR);
+        return branch64(Equal, tempGPR, TrustedImm32(JSValue::BigInt32Tag));
+    }
+    Jump branchIfNotBigInt32KnownNotNumber(JSValueRegs regs, GPRReg tempGPR)
+    {
+        return branchIfNotBigInt32KnownNotNumber(regs.gpr(), tempGPR);
+    }
+    Jump branchIfNotBigInt32KnownNotNumber(GPRReg gpr, GPRReg tempGPR)
+    {
+        ASSERT(tempGPR != InvalidGPRReg);
+        move(gpr, tempGPR);
+        and64(TrustedImm32(JSValue::BigInt32Tag), tempGPR);
+        return branch64(NotEqual, tempGPR, TrustedImm32(JSValue::BigInt32Tag));
+    }
+#endif // USE(BIGINT32)
+
+    // FIXME: rename these to make it clear that they require their input to be a cell.
</ins><span class="cx">     Jump branchIfObject(GPRReg cellGPR)
</span><span class="cx">     {
</span><span class="cx">         return branch8(
</span><span class="lines">@@ -951,13 +990,14 @@
</span><span class="cx">     {
</span><span class="cx">         return branch8(NotEqual, Address(cellGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(type));
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    // FIXME: rename these to make it clear that they require their input to be a cell.
</ins><span class="cx">     Jump branchIfString(GPRReg cellGPR) { return branchIfType(cellGPR, StringType); }
</span><span class="cx">     Jump branchIfNotString(GPRReg cellGPR) { return branchIfNotType(cellGPR, StringType); }
</span><span class="cx">     Jump branchIfSymbol(GPRReg cellGPR) { return branchIfType(cellGPR, SymbolType); }
</span><span class="cx">     Jump branchIfNotSymbol(GPRReg cellGPR) { return branchIfNotType(cellGPR, SymbolType); }
</span><del>-    Jump branchIfBigInt(GPRReg cellGPR) { return branchIfType(cellGPR, BigIntType); }
-    Jump branchIfNotBigInt(GPRReg cellGPR) { return branchIfNotType(cellGPR, BigIntType); }
</del><ins>+    Jump branchIfHeapBigInt(GPRReg cellGPR) { return branchIfType(cellGPR, HeapBigIntType); }
+    Jump branchIfNotHeapBigInt(GPRReg cellGPR) { return branchIfNotType(cellGPR, HeapBigIntType); }
</ins><span class="cx">     Jump branchIfFunction(GPRReg cellGPR) { return branchIfType(cellGPR, JSFunctionType); }
</span><span class="cx">     Jump branchIfNotFunction(GPRReg cellGPR) { return branchIfNotType(cellGPR, JSFunctionType); }
</span><span class="cx">     
</span><span class="lines">@@ -1356,6 +1396,19 @@
</span><span class="cx">         
</span><span class="cx">         done.link(this);
</span><span class="cx">     }
</span><ins>+#endif // USE(JSVALUE64)
+
+#if USE(BIGINT32)
+    void unboxBigInt32(GPRReg gpr)
+    {
+        urshift64(trustedImm32ForShift(Imm32(16)), gpr);
+    }
+
+    void boxBigInt32(GPRReg gpr)
+    {
+        lshift64(trustedImm32ForShift(Imm32(16)), gpr);
+        or64(TrustedImm32(JSValue::BigInt32Tag), gpr);
+    }
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="lines">@@ -1715,7 +1768,7 @@
</span><span class="cx">         //         }
</span><span class="cx">         //     } else if (is string) {
</span><span class="cx">         //         return string
</span><del>-        //     } else if (is bigint) {
</del><ins>+        //     } else if (is heapbigint) {
</ins><span class="cx">         //         return bigint
</span><span class="cx">         //     } else {
</span><span class="cx">         //         return symbol
</span><span class="lines">@@ -1726,6 +1779,8 @@
</span><span class="cx">         //     return object
</span><span class="cx">         // } else if (is boolean) {
</span><span class="cx">         //     return boolean
</span><ins>+        // } else if (is bigint32) {
+        //     return bigint
</ins><span class="cx">         // } else {
</span><span class="cx">         //     return undefined
</span><span class="cx">         // }
</span><span class="lines">@@ -1757,10 +1812,10 @@
</span><span class="cx"> 
</span><span class="cx">         notString.link(this);
</span><span class="cx"> 
</span><del>-        Jump notBigInt = branchIfNotBigInt(cellGPR);
</del><ins>+        Jump notHeapBigInt = branchIfNotHeapBigInt(cellGPR);
</ins><span class="cx">         functor(TypeofType::BigInt, false);
</span><span class="cx"> 
</span><del>-        notBigInt.link(this);
</del><ins>+        notHeapBigInt.link(this);
</ins><span class="cx">         functor(TypeofType::Symbol, false);
</span><span class="cx">         
</span><span class="cx">         notCell.link(this);
</span><span class="lines">@@ -1776,6 +1831,12 @@
</span><span class="cx">         Jump notBoolean = branchIfNotBoolean(regs, tempGPR);
</span><span class="cx">         functor(TypeofType::Boolean, false);
</span><span class="cx">         notBoolean.link(this);
</span><ins>+
+#if USE(BIGINT32)
+        Jump notBigInt32 = branchIfNotBigInt32KnownNotNumber(regs, tempGPR);
+        functor(TypeofType::BigInt, false);
+        notBigInt32.link(this);
+#endif
</ins><span class="cx">         
</span><span class="cx">         functor(TypeofType::Undefined, true);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JIT.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JIT.cpp  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/jit/JIT.cpp     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -370,6 +370,7 @@
</span><span class="cx">         DEFINE_OP(op_is_undefined_or_null)
</span><span class="cx">         DEFINE_OP(op_is_boolean)
</span><span class="cx">         DEFINE_OP(op_is_number)
</span><ins>+        DEFINE_OP(op_is_big_int)
</ins><span class="cx">         DEFINE_OP(op_is_object)
</span><span class="cx">         DEFINE_OP(op_is_cell_with_type)
</span><span class="cx">         DEFINE_OP(op_jeq_null)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JIT.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JIT.h    2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/jit/JIT.h       2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -531,6 +531,11 @@
</span><span class="cx">         void emit_op_is_undefined_or_null(const Instruction*);
</span><span class="cx">         void emit_op_is_boolean(const Instruction*);
</span><span class="cx">         void emit_op_is_number(const Instruction*);
</span><ins>+#if USE(BIGINT32)
+        void emit_op_is_big_int(const Instruction*);
+#else
+        NO_RETURN void emit_op_is_big_int(const Instruction*);
+#endif
</ins><span class="cx">         void emit_op_is_object(const Instruction*);
</span><span class="cx">         void emit_op_is_cell_with_type(const Instruction*);
</span><span class="cx">         void emit_op_jeq_null(const Instruction*);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITArithmeticcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITArithmetic.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITArithmetic.cpp        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/jit/JITArithmetic.cpp   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -476,6 +476,7 @@
</span><span class="cx">     UnaryArithProfile* arithProfile = &currentInstruction->as<OpNegate>().metadata(m_codeBlock).m_arithProfile;
</span><span class="cx">     JITNegIC* negateIC = m_codeBlock->addJITNegIC(arithProfile);
</span><span class="cx">     m_instructionToMathIC.add(currentInstruction, negateIC);
</span><ins>+    // FIXME: it would be better to call those operationValueNegate, since the operand can be a BigInt
</ins><span class="cx">     emitMathICFast<OpNegate>(negateIC, currentInstruction, operationArithNegateProfiled, operationArithNegate);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -484,6 +485,7 @@
</span><span class="cx">     linkAllSlowCases(iter);
</span><span class="cx"> 
</span><span class="cx">     JITNegIC* negIC = bitwise_cast<JITNegIC*>(m_instructionToMathIC.get(currentInstruction));
</span><ins>+    // FIXME: it would be better to call those operationValueNegate, since the operand can be a BigInt
</ins><span class="cx">     emitMathICSlow<OpNegate>(negIC, currentInstruction, operationArithNegateProfiledOptimize, operationArithNegateProfiled, operationArithNegateOptimize);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2009-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2009-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -283,6 +283,37 @@
</span><span class="cx">     emitPutVirtualRegister(dst);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+void JIT::emit_op_is_big_int(const Instruction* currentInstruction)
+{
+    auto bytecode = currentInstruction->as<OpIsBigInt>();
+    VirtualRegister dst = bytecode.m_dst;
+    VirtualRegister value = bytecode.m_operand;
+
+    emitGetVirtualRegister(value, regT0);
+    Jump isCell = branchIfCell(regT0);
+
+    move(TrustedImm64(JSValue::BigInt32Mask), regT1);
+    and64(regT1, regT0);
+    compare64(Equal, regT0, TrustedImm32(JSValue::BigInt32Tag), regT0);
+    boxBoolean(regT0, JSValueRegs { regT0 });
+    Jump done = jump();
+
+    isCell.link(this);
+    compare8(Equal, Address(regT0, JSCell::typeInfoTypeOffset()), TrustedImm32(HeapBigIntType), regT0);
+    boxBoolean(regT0, JSValueRegs { regT0 });
+
+    done.link(this);
+    emitPutVirtualRegister(dst);
+}
+#else // if !USE(BIGINT32)
+NO_RETURN void JIT::emit_op_is_big_int(const Instruction*)
+{
+    // If we only have HeapBigInts, then we emit isCellWithType instead of isBigInt.
+    RELEASE_ASSERT_NOT_REACHED();
+}
+#endif
+
</ins><span class="cx"> void JIT::emit_op_is_cell_with_type(const Instruction* currentInstruction)
</span><span class="cx"> {
</span><span class="cx">     auto bytecode = currentInstruction->as<OpIsCellWithType>();
</span><span class="lines">@@ -570,12 +601,53 @@
</span><span class="cx">     VirtualRegister src2 = bytecode.m_rhs;
</span><span class="cx"> 
</span><span class="cx">     emitGetVirtualRegisters(src1, regT0, src2, regT1);
</span><del>-    
</del><ins>+
+#if USE(BIGINT32)
+    /* At a high level we do (assuming 'type' to be StrictEq):
+    If (left is Double || right is Double)
+        goto slowPath;
+    result = (left == right);
+    if (result)
+        goto done;
+    if (left is Cell || right is Cell)
+        goto slowPath;
+    done:
+    return result;
+    */
+
+    // This fragment implements (left is Double || right is Double), with a single branch instead of the 4 that would be naively required if we used branchIfInt32/branchIfNumber
+    // The trick is that if a JSValue is an Int32, then adding 1<<49 to it will make it overflow, leaving all high bits at 0
+    // If it is not a number at all, then 1<<49 will be its only high bit set
+    // Leaving only doubles above or equal 1<<50.
+    move(regT0, regT2);
+    move(regT1, regT3);
+    move(TrustedImm64(JSValue::LowestOfHighBits), regT5);
+    add64(regT5, regT2);
+    add64(regT5, regT3);
+    lshift64(TrustedImm32(1), regT5);
+    or64(regT2, regT3);
+    addSlowCase(branch64(AboveOrEqual, regT3, regT5));
+
+    compare64(Equal, regT0, regT1, regT5);
+    Jump done = branchTest64(NonZero, regT5);
+
+    move(regT0, regT2);
+    // Jump slow if at least one is a cell (to cover strings and BigInts).
+    and64(regT1, regT2);
+    // FIXME: we could do something more precise: unless there is a BigInt32, we only need to do the slow path if both are strings
+    addSlowCase(branchIfCell(regT2));
+
+    done.link(this);
+    if (type == CompileOpStrictEqType::NStrictEq)
+        xor64(TrustedImm64(1), regT5);
+    boxBoolean(regT5, JSValueRegs { regT5 });
+    emitPutVirtualRegister(dst, regT5);
+#else // if !USE(BIGINT32)
</ins><span class="cx">     // Jump slow if both are cells (to cover strings).
</span><span class="cx">     move(regT0, regT2);
</span><span class="cx">     or64(regT1, regT2);
</span><span class="cx">     addSlowCase(branchIfCell(regT2));
</span><del>-    
</del><ins>+
</ins><span class="cx">     // Jump slow if either is a double. First test if it's an integer, which is fine, and then test
</span><span class="cx">     // if it's a double.
</span><span class="cx">     Jump leftOK = branchIfInt32(regT0);
</span><span class="lines">@@ -592,6 +664,7 @@
</span><span class="cx">     boxBoolean(regT0, JSValueRegs { regT0 });
</span><span class="cx"> 
</span><span class="cx">     emitPutVirtualRegister(dst);
</span><ins>+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JIT::emit_op_stricteq(const Instruction* currentInstruction)
</span><span class="lines">@@ -614,6 +687,45 @@
</span><span class="cx"> 
</span><span class="cx">     emitGetVirtualRegisters(src1, regT0, src2, regT1);
</span><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+    /* At a high level we do (assuming 'type' to be StrictEq):
+    If (left is Double || right is Double)
+       goto slowPath;
+    if (left == right)
+       goto taken;
+    if (left is Cell || right is Cell)
+       goto slowPath;
+    goto notTaken;
+    */
+
+    // This fragment implements (left is Double || right is Double), with a single branch instead of the 4 that would be naively required if we used branchIfInt32/branchIfNumber
+    // The trick is that if a JSValue is an Int32, then adding 1<<49 to it will make it overflow, leaving all high bits at 0
+    // If it is not a number at all, then 1<<49 will be its only high bit set
+    // Leaving only doubles above or equal 1<<50.
+    move(regT0, regT2);
+    move(regT1, regT3);
+    move(TrustedImm64(JSValue::LowestOfHighBits), regT5);
+    add64(regT5, regT2);
+    add64(regT5, regT3);
+    lshift64(TrustedImm32(1), regT5);
+    or64(regT2, regT3);
+    addSlowCase(branch64(AboveOrEqual, regT3, regT5));
+
+    Jump areEqual = branch64(Equal, regT0, regT1);
+    if (type == CompileOpStrictEqType::StrictEq)
+        addJump(areEqual, target);
+
+    move(regT0, regT2);
+    // Jump slow if at least one is a cell (to cover strings and BigInts).
+    and64(regT1, regT2);
+    // FIXME: we could do something more precise: unless there is a BigInt32, we only need to do the slow path if both are strings
+    addSlowCase(branchIfCell(regT2));
+
+    if (type == CompileOpStrictEqType::NStrictEq) {
+        addJump(jump(), target);
+        areEqual.link(this);
+    }
+#else // if !USE(BIGINT32)
</ins><span class="cx">     // Jump slow if both are cells (to cover strings).
</span><span class="cx">     move(regT0, regT2);
</span><span class="cx">     or64(regT1, regT2);
</span><span class="lines">@@ -627,11 +739,11 @@
</span><span class="cx">     Jump rightOK = branchIfInt32(regT1);
</span><span class="cx">     addSlowCase(branchIfNumber(regT1));
</span><span class="cx">     rightOK.link(this);
</span><del>-
</del><span class="cx">     if (type == CompileOpStrictEqType::StrictEq)
</span><span class="cx">         addJump(branch64(Equal, regT1, regT0), target);
</span><span class="cx">     else
</span><span class="cx">         addJump(branch64(NotEqual, regT1, regT0), target);
</span><ins>+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JIT::emit_op_jstricteq(const Instruction* currentInstruction)
</span><span class="lines">@@ -686,7 +798,7 @@
</span><span class="cx">     emitGetVirtualRegister(srcVReg, regT0);
</span><span class="cx"> 
</span><span class="cx">     Jump isNotCell = branchIfNotCell(regT0);
</span><del>-    addSlowCase(branchIfNotBigInt(regT0));
</del><ins>+    addSlowCase(branchIfNotHeapBigInt(regT0));
</ins><span class="cx">     Jump isBigInt = jump();
</span><span class="cx"> 
</span><span class="cx">     isNotCell.link(this);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOpcodes32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -288,6 +288,12 @@
</span><span class="cx">     emitStoreBool(dst, regT0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+NO_RETURN void JIT::emit_op_is_big_int(const Instruction*)
+{
+    // We emit is_cell_with_type instead, since BigInt32 is not supported on 32-bit platforms.
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
</ins><span class="cx"> void JIT::emit_op_is_cell_with_type(const Instruction* currentInstruction)
</span><span class="cx"> {
</span><span class="cx">     auto bytecode = currentInstruction->as<OpIsCellWithType>();
</span><span class="lines">@@ -866,7 +872,7 @@
</span><span class="cx">     emitLoad(src, regT1, regT0);
</span><span class="cx"> 
</span><span class="cx">     Jump isNotCell = branchIfNotCell(regT1);
</span><del>-    addSlowCase(branchIfNotBigInt(regT0));
</del><ins>+    addSlowCase(branchIfNotHeapBigInt(regT0));
</ins><span class="cx">     Jump isBigInt = jump();
</span><span class="cx"> 
</span><span class="cx">     isNotCell.link(this);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.cpp        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.cpp   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1325,6 +1325,19 @@
</span><span class="cx">     return JSValue::strictEqual(globalObject, src1, src2);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+size_t JIT_OPERATION operationCompareEqHeapBigIntToInt32(JSGlobalObject* globalObject, JSCell* heapBigInt, int32_t smallInt)
+{
+    VM& vm = globalObject->vm();
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+
+    ASSERT(heapBigInt->isHeapBigInt());
+
+    return static_cast<JSBigInt*>(heapBigInt)->equalsToInt32(smallInt);
+}
+#endif
+
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationNewArrayWithProfile(JSGlobalObject* globalObject, ArrayAllocationProfile* profile, const JSValue* values, int size)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="lines">@@ -2848,6 +2861,7 @@
</span><span class="cx">     return profiledMul(globalObject, encodedOp1, encodedOp2, *arithProfile);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// FIXME: it would be better to call those operationValueNegate, since the operand can be a BigInt
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationArithNegate(JSGlobalObject* globalObject, EncodedJSValue encodedOperand)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="lines">@@ -2860,8 +2874,16 @@
</span><span class="cx">     JSValue primValue = operand.toPrimitive(globalObject, PreferNumber);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="cx"> 
</span><del>-    if (primValue.isBigInt())
-        return JSValue::encode(JSBigInt::unaryMinus(vm, asBigInt(primValue)));
</del><ins>+#if USE(BIGINT32)
+    if (primValue.isBigInt32()) {
+        int32_t value = primValue.bigInt32AsInt32();
+        if (value != INT_MIN)
+            return JSValue::encode(JSValue(JSValue::JSBigInt32, -value));
+        primValue = JSBigInt::createFrom(vm, value);
+    }
+#endif
+    if (primValue.isHeapBigInt())
+        return JSValue::encode(JSBigInt::unaryMinus(vm, primValue.asHeapBigInt()));
</ins><span class="cx"> 
</span><span class="cx">     double number = primValue.toNumber(globalObject);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="lines">@@ -2869,6 +2891,7 @@
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// FIXME: it would be better to call those operationValueNegate, since the operand can be a BigInt
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationArithNegateProfiled(JSGlobalObject* globalObject, EncodedJSValue encodedOperand, UnaryArithProfile* arithProfile)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(arithProfile);
</span><span class="lines">@@ -2883,10 +2906,20 @@
</span><span class="cx">     JSValue primValue = operand.toPrimitive(globalObject);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="cx"> 
</span><del>-    if (primValue.isBigInt()) {
-        JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue));
</del><ins>+#if USE(BIGINT32)
+    if (primValue.isBigInt32()) {
+        int32_t value = primValue.bigInt32AsInt32();
+        if (value != INT_MIN) {
+            auto result = JSValue(JSValue::JSBigInt32, -value);
+            arithProfile->observeResult(result);
+            return JSValue::encode(result);
+        }
+        primValue = JSBigInt::createFrom(vm, value);
+    }
+#endif
+    if (primValue.isHeapBigInt()) {
+        JSBigInt* result = JSBigInt::unaryMinus(vm, primValue.asHeapBigInt());
</ins><span class="cx">         arithProfile->observeResult(result);
</span><del>-
</del><span class="cx">         return JSValue::encode(result);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -2897,6 +2930,7 @@
</span><span class="cx">     return JSValue::encode(result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// FIXME: it would be better to call those operationValueNegate, since the operand can be a BigInt
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationArithNegateProfiledOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOperand, JITNegIC* negIC)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="lines">@@ -2917,9 +2951,20 @@
</span><span class="cx">     
</span><span class="cx">     JSValue primValue = operand.toPrimitive(globalObject);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><del>-    
-    if (primValue.isBigInt()) {
-        JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue));
</del><ins>+
+#if USE(BIGINT32)
+    if (primValue.isBigInt32()) {
+        int32_t value = primValue.bigInt32AsInt32();
+        if (value != INT_MIN) {
+            auto result = JSValue(JSValue::JSBigInt32, -value);
+            arithProfile->observeResult(result);
+            return JSValue::encode(result);
+        }
+        primValue = JSBigInt::createFrom(vm, value);
+    }
+#endif
+    if (primValue.isHeapBigInt()) {
+        JSBigInt* result = JSBigInt::unaryMinus(vm, primValue.asHeapBigInt());
</ins><span class="cx">         arithProfile->observeResult(result);
</span><span class="cx">         return JSValue::encode(result);
</span><span class="cx">     }
</span><span class="lines">@@ -2931,6 +2976,7 @@
</span><span class="cx">     return JSValue::encode(result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// FIXME: it would be better to call those operationValueNegate, since the operand can be a BigInt
</ins><span class="cx"> EncodedJSValue JIT_OPERATION operationArithNegateOptimize(JSGlobalObject* globalObject, EncodedJSValue encodedOperand, JITNegIC* negIC)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="lines">@@ -2950,10 +2996,19 @@
</span><span class="cx"> 
</span><span class="cx">     JSValue primValue = operand.toPrimitive(globalObject);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><del>-    
-    if (primValue.isBigInt())
-        return JSValue::encode(JSBigInt::unaryMinus(vm, asBigInt(primValue)));
</del><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+    // FIXME: why does this function profile the argument but not the result?
+    if (primValue.isBigInt32()) {
+        int32_t value = primValue.bigInt32AsInt32();
+        if (value != INT_MIN)
+            return JSValue::encode(JSValue(JSValue::JSBigInt32, -value));
+        primValue = JSBigInt::createFrom(vm, value);
+    }
+#endif
+    if (primValue.isHeapBigInt())
+        return JSValue::encode(JSBigInt::unaryMinus(vm, primValue.asHeapBigInt()));
+
</ins><span class="cx">     double number = primValue.toNumber(globalObject);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="cx">     return JSValue::encode(jsNumber(-number));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITOperations.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITOperations.h  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/jit/JITOperations.h     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -207,6 +207,7 @@
</span><span class="cx"> size_t JIT_OPERATION operationCompareStrictEq(JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationCompareStringEq(JSGlobalObject*, JSCell* left, JSCell* right) WTF_INTERNAL;
</span><ins>+size_t JIT_OPERATION operationCompareEqHeapBigIntToInt32(JSGlobalObject*, JSCell* heapBigInt, int32_t smallInt) WTF_INTERNAL;
</ins><span class="cx"> #else
</span><span class="cx"> size_t JIT_OPERATION operationCompareStringEq(JSGlobalObject*, JSCell* left, JSCell* right) WTF_INTERNAL;
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLLIntOfflineAsmConfigh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -136,6 +136,12 @@
</span><span class="cx"> #define OFFLINE_ASM_JSVALUE64 0
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+#define OFFLINE_ASM_BIGINT32 1
+#else
+#define OFFLINE_ASM_BIGINT32 0
+#endif
+
</ins><span class="cx"> #if CPU(ADDRESS64)
</span><span class="cx"> #define OFFLINE_ASM_ADDRESS64 1
</span><span class="cx"> #else
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreterasm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -196,6 +196,11 @@
</span><span class="cx">     const ValueNull       = constexpr JSValue::ValueNull
</span><span class="cx">     const TagNumber       = constexpr JSValue::NumberTag
</span><span class="cx">     const NotCellMask     = constexpr JSValue::NotCellMask
</span><ins>+    if BIGINT32
+        const TagBigInt32 = constexpr JSValue::BigInt32Tag
+        const MaskBigInt32 = constexpr JSValue::BigInt32Mask
+    end
+    const LowestOfHighBits = constexpr JSValue::LowestOfHighBits
</ins><span class="cx"> else
</span><span class="cx">     const Int32Tag = constexpr JSValue::Int32Tag
</span><span class="cx">     const BooleanTag = constexpr JSValue::BooleanTag
</span><span class="lines">@@ -521,6 +526,7 @@
</span><span class="cx"> const ArrayType = constexpr ArrayType
</span><span class="cx"> const DerivedArrayType = constexpr DerivedArrayType
</span><span class="cx"> const ProxyObjectType = constexpr ProxyObjectType
</span><ins>+const HeapBigIntType = constexpr HeapBigIntType
</ins><span class="cx"> 
</span><span class="cx"> # The typed array types need to be numbered in a particular order because of the manually written
</span><span class="cx"> # switch statement in get_by_val and put_by_val.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1307,6 +1307,12 @@
</span><span class="cx"> end)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+# On 32-bit platforms BIGINT32 is not supported, so we generate op_is_cell_with_type instead of op_is_big_int
+llintOp(op_is_big_int, OpIsBigInt, macro(unused, unused, unused)
+    notSupported()
+end)
+
+
</ins><span class="cx"> llintOpWithReturn(op_is_cell_with_type, OpIsCellWithType, macro (size, get, dispatch, return)
</span><span class="cx">     get(m_operand, t1)
</span><span class="cx">     loadConstantOrVariable(size, t1, t0, t3)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-# Copyright (C) 2011-2019 Apple Inc. All rights reserved.
</del><ins>+# Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx"> #
</span><span class="cx"> # Redistribution and use in source and binary forms, with or without
</span><span class="cx"> # modification, are permitted provided that the following conditions
</span><span class="lines">@@ -844,25 +844,49 @@
</span><span class="cx"> end)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-macro strictEqOp(opcodeName, opcodeStruct, equalityOperation)
</del><ins>+macro strictEqOp(opcodeName, opcodeStruct, createBoolean)
</ins><span class="cx">     llintOpWithReturn(op_%opcodeName%, opcodeStruct, macro (size, get, dispatch, return)
</span><span class="cx">         get(m_rhs, t0)
</span><span class="cx">         get(m_lhs, t2)
</span><span class="cx">         loadConstantOrVariable(size, t0, t1)
</span><span class="cx">         loadConstantOrVariable(size, t2, t0)
</span><ins>+
+        # At a high level we do
+        # If (left is Double || right is Double)
+        #     goto slowPath;
+        # result = (left == right);
+        # if (result)
+        #     goto done;
+        # if (left is Cell || right is Cell)
+        #     goto slowPath;
+        # done:
+        # return result;
+
+        # This fragment implements (left is Double || right is Double), with a single branch instead of the 4 that would be naively required if we used branchIfInt32/branchIfNumber
+        # The trick is that if a JSValue is an Int32, then adding 1<<49 to it will make it overflow, leaving all high bits at 0
+        # If it is not a number at all, then 1<<49 will be its only high bit set
+        # Leaving only doubles above or equal 1<<50.
</ins><span class="cx">         move t0, t2
</span><del>-        orq t1, t2
</del><ins>+        move t1, t3
+        move LowestOfHighBits, t5
+        addq t5, t2
+        addq t5, t3
+        orq t2, t3
+        lshiftq 1, t5
+        bqaeq t3, t5, .slow
+
+        cqeq t0, t1, t5
+        btqnz t5, t5, .done #is there a better way of checking t5 != 0 ?
+
+        move t0, t2
+        # This andq could be an 'or' if not for BigInt32 (since it makes it possible for a Cell to be strictEqual to a non-Cell)
+        andq t1, t2
</ins><span class="cx">         btqz t2, notCellMask, .slow
</span><del>-        bqaeq t0, numberTag, .leftOK
-        btqnz t0, numberTag, .slow
-    .leftOK:
-        bqaeq t1, numberTag, .rightOK
-        btqnz t1, numberTag, .slow
-    .rightOK:
-        equalityOperation(t0, t1, t0)
-        orq ValueFalse, t0
-        return(t0)
</del><span class="cx"> 
</span><ins>+    .done:
+        createBoolean(t5)
+        return(t5)
+
</ins><span class="cx">     .slow:
</span><span class="cx">         callSlowPath(_slow_path_%opcodeName%)
</span><span class="cx">         dispatch()
</span><span class="lines">@@ -871,34 +895,54 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> strictEqOp(stricteq, OpStricteq,
</span><del>-    macro (left, right, result) cqeq left, right, result end)
</del><ins>+    macro (operand) xorq ValueFalse, operand end)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> strictEqOp(nstricteq, OpNstricteq,
</span><del>-    macro (left, right, result) cqneq left, right, result end)
</del><ins>+    macro (operand) xorq ValueTrue, operand end)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-macro strictEqualityJumpOp(opcodeName, opcodeStruct, equalityOperation)
</del><ins>+macro strictEqualityJumpOp(opcodeName, opcodeStruct, jumpIfEqual, jumpIfNotEqual)
</ins><span class="cx">     llintOpWithJump(op_%opcodeName%, opcodeStruct, macro (size, get, jump, dispatch)
</span><span class="cx">         get(m_lhs, t2)
</span><span class="cx">         get(m_rhs, t3)
</span><span class="cx">         loadConstantOrVariable(size, t2, t0)
</span><span class="cx">         loadConstantOrVariable(size, t3, t1)
</span><ins>+
+        # At a high level we do
+        # If (left is Double || right is Double)
+        #     goto slowPath;
+        # if (left == right)
+        #     goto jumpTarget;
+        # if (left is Cell || right is Cell)
+        #     goto slowPath;
+        # goto otherJumpTarget
+
+        # This fragment implements (left is Double || right is Double), with a single branch instead of the 4 that would be naively required if we used branchIfInt32/branchIfNumber
+        # The trick is that if a JSValue is an Int32, then adding 1<<49 to it will make it overflow, leaving all high bits at 0
+        # If it is not a number at all, then 1<<49 will be its only high bit set
+        # Leaving only doubles above or equal 1<<50.
</ins><span class="cx">         move t0, t2
</span><del>-        orq t1, t2
</del><ins>+        move t1, t3
+        move LowestOfHighBits, t5
+        addq t5, t2
+        addq t5, t3
+        orq t2, t3
+        lshiftq 1, t5
+        bqaeq t3, t5, .slow
+
+        bqeq t0, t1, .equal
+
+        move t0, t2
+        # This andq could be an 'or' if not for BigInt32 (since it makes it possible for a Cell to be strictEqual to a non-Cell)
+        andq t1, t2
</ins><span class="cx">         btqz t2, notCellMask, .slow
</span><del>-        bqaeq t0, numberTag, .leftOK
-        btqnz t0, numberTag, .slow
-    .leftOK:
-        bqaeq t1, numberTag, .rightOK
-        btqnz t1, numberTag, .slow
-    .rightOK:
-        equalityOperation(t0, t1, .jumpTarget)
-        dispatch()
</del><span class="cx"> 
</span><del>-    .jumpTarget:
-        jump(m_targetLabel)
</del><ins>+        jumpIfNotEqual(jump, m_targetLabel, dispatch)
</ins><span class="cx"> 
</span><ins>+    .equal:
+        jumpIfEqual(jump, m_targetLabel, dispatch)
+
</ins><span class="cx">     .slow:
</span><span class="cx">         callSlowPath(_llint_slow_path_%opcodeName%)
</span><span class="cx">         nextInstruction()
</span><span class="lines">@@ -907,26 +951,28 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> strictEqualityJumpOp(jstricteq, OpJstricteq,
</span><del>-    macro (left, right, target) bqeq left, right, target end)
</del><ins>+    macro (jump, targetLabel, dispatch) jump(targetLabel) end,
+    macro (jump, targetLabel, dispatch) dispatch() end)
</ins><span class="cx"> 
</span><del>-
</del><span class="cx"> strictEqualityJumpOp(jnstricteq, OpJnstricteq,
</span><del>-    macro (left, right, target) bqneq left, right, target end)
</del><ins>+    macro (jump, targetLabel, dispatch) dispatch() end,
+    macro (jump, targetLabel, dispatch) jump(targetLabel) end)
</ins><span class="cx"> 
</span><span class="cx"> macro preOp(opcodeName, opcodeStruct, integerOperation)
</span><span class="cx">     llintOpWithMetadata(op_%opcodeName%, opcodeStruct, macro (size, get, dispatch, metadata, return)
</span><span class="cx">         macro updateArithProfile(type)
</span><del>-            orh type, %opcodeStruct%::Metadata::m_arithProfile + UnaryArithProfile::m_bits[t1]
</del><ins>+            orh type, %opcodeStruct%::Metadata::m_arithProfile + UnaryArithProfile::m_bits[t2]
</ins><span class="cx">         end
</span><span class="cx"> 
</span><span class="cx">         get(m_srcDst, t0)
</span><del>-        loadq [cfr, t0, 8], t3
-        metadata(t1, t2)
-        # Metadata in t1, srcDst in t3
-        bqb t3, numberTag, .slow
-        integerOperation(t3, .slow)
-        orq numberTag, t3
-        storeq t3, [cfr, t0, 8]
</del><ins>+        loadq [cfr, t0, 8], t1
+        metadata(t2, t3)
+        # srcDst in t1, metadata in t2
+        # FIXME: the next line jumps to the slow path for BigInt32. We could instead have a dedicated path in here for them.
+        bqb t1, numberTag, .slow
+        integerOperation(t1, .slow)
+        orq numberTag, t1
+        storeq t1, [cfr, t0, 8]
</ins><span class="cx">         updateArithProfile(ArithProfileInt)
</span><span class="cx">         dispatch()
</span><span class="cx"> 
</span><span class="lines">@@ -934,6 +980,7 @@
</span><span class="cx">         callSlowPath(_slow_path_%opcodeName%)
</span><span class="cx">         dispatch()
</span><span class="cx">     end)
</span><ins>+
</ins><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> llintOpWithProfile(op_to_number, OpToNumber, macro (size, get, dispatch, return)
</span><span class="lines">@@ -1279,6 +1326,26 @@
</span><span class="cx">     return(t1)
</span><span class="cx"> end)
</span><span class="cx"> 
</span><ins>+if BIGINT32
+    llintOpWithReturn(op_is_big_int, OpIsBigInt, macro(size, get, dispatch, return)
+        get(m_operand, t1)
+        loadConstantOrVariable(size, t1, t0)
+        btqnz t0, notCellMask, .notCellCase
+        cbeq JSCell::m_type[t0], HeapBigIntType, t1
+        orq ValueFalse, t1
+        return(t1)
+    .notCellCase:
+        andq MaskBigInt32, t0
+        cqeq t0, TagBigInt32, t0
+        orq ValueFalse, t0
+        return(t0)
+    end)
+else
+# if BIGINT32 is not supported we generate op_is_cell_with_type instead of op_is_big_int
+    llintOp(op_is_big_int, OpIsBigInt, macro(unused, unused, unused)
+        notSupported()
+    end)
+end
</ins><span class="cx"> 
</span><span class="cx"> llintOpWithReturn(op_is_cell_with_type, OpIsCellWithType, macro (size, get, dispatch, return)
</span><span class="cx">     getu(size, OpIsCellWithType, m_type, t0)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParserArenacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/ParserArena.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/ParserArena.cpp       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/parser/ParserArena.cpp  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -83,6 +83,10 @@
</span><span class="cx">     if (radix == 10)
</span><span class="cx">         return identifier;
</span><span class="cx"> 
</span><ins>+    auto scope = DECLARE_CATCH_SCOPE(vm);
+    JSValue bigInt = JSBigInt::parseInt(nullptr, vm, identifier.string(), radix, JSBigInt::ErrorParseMode::ThrowExceptions, JSBigInt::ParseIntSign::Unsigned);
+    scope.assertNoException();
+
</ins><span class="cx">     // FIXME: We are allocating a JSBigInt just to be able to use
</span><span class="cx">     // JSBigInt::tryGetString when radix is not 10.
</span><span class="cx">     // This creates some GC pressure, but since these identifiers
</span><span class="lines">@@ -90,11 +94,15 @@
</span><span class="cx">     // it wont be much problematic, given such cases are very rare.
</span><span class="cx">     // There is a lot of optimizations we can apply here when necessary.
</span><span class="cx">     // https://bugs.webkit.org/show_bug.cgi?id=207627
</span><ins>+    JSBigInt* heapBigInt;
+#if USE(BIGINT32)
+    if (bigInt.isBigInt32())
+        heapBigInt = JSBigInt::createFrom(vm, bigInt.bigInt32AsInt32());
+    else
+#endif
+        heapBigInt = bigInt.asHeapBigInt();
</ins><span class="cx"> 
</span><del>-    auto scope = DECLARE_CATCH_SCOPE(vm);
-    JSBigInt* bigInt = JSBigInt::parseInt(nullptr, vm, identifier.string(), radix, JSBigInt::ErrorParseMode::ThrowExceptions, JSBigInt::ParseIntSign::Unsigned);
-    scope.assertNoException();
-    m_identifiers.append(Identifier::fromString(vm, JSBigInt::tryGetString(vm, bigInt, 10)));
</del><ins>+    m_identifiers.append(Identifier::fromString(vm, JSBigInt::tryGetString(vm, heapBigInt, 10)));
</ins><span class="cx">     return m_identifiers.last();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeArrayPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/ArrayPrototype.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -43,7 +43,6 @@
</span><span class="cx"> #include "Lookup.h"
</span><span class="cx"> #include "ObjectConstructor.h"
</span><span class="cx"> #include "ObjectPrototype.h"
</span><del>-#include "Operations.h"
</del><span class="cx"> #include "StringRecursionChecker.h"
</span><span class="cx"> #include <algorithm>
</span><span class="cx"> #include <wtf/Assertions.h>
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeBigIntConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/BigIntConstructor.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/BigIntConstructor.cpp        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/BigIntConstructor.cpp   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2017 Caio Lima <ticaiolima@gmail.com>
</span><del>- * Copyright (C) 2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -75,18 +75,6 @@
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ Functions ---------------------------
</span><span class="cx"> 
</span><del>-static bool isSafeInteger(JSValue argument)
-{
-    if (argument.isInt32())
-        return true;
-
-    if (!argument.isDouble())
-        return false;
-
-    double number = argument.asDouble();
-    return trunc(number) == number && std::abs(number) <= maxSafeInteger();
-}
-
</del><span class="cx"> static EncodedJSValue toBigInt(JSGlobalObject* globalObject, JSValue argument)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(argument.isPrimitive());
</span><span class="lines">@@ -94,20 +82,24 @@
</span><span class="cx">     
</span><span class="cx">     if (argument.isBigInt())
</span><span class="cx">         return JSValue::encode(argument);
</span><del>-    
</del><ins>+
+    if (argument.isBoolean()) {
+#if USE(BIGINT32)
+        return JSValue::encode(JSValue(JSValue::JSBigInt32, argument.asBoolean()));
+#else
+        return JSValue::encode(JSBigInt::createFrom(vm, argument.asBoolean()));
+#endif
+    }
+
+    if (argument.isString()) {
+        return toStringView(globalObject, argument, [&] (StringView view) {
+            return JSValue::encode(JSBigInt::parseInt(globalObject, view));
+        });
+    }
+
+    ASSERT(argument.isUndefinedOrNull() || argument.isNumber() || argument.isSymbol());
</ins><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><del>-    
-    if (argument.isBoolean())
-        RELEASE_AND_RETURN(scope, JSValue::encode(JSBigInt::createFrom(vm, argument.asBoolean())));
-    
-    if (argument.isUndefinedOrNull() || argument.isNumber() || argument.isSymbol())
-        return throwVMTypeError(globalObject, scope, "Invalid argument type in ToBigInt operation"_s);
-    
-    ASSERT(argument.isString());
-    
-    RELEASE_AND_RETURN(scope, toStringView(globalObject, argument, [&] (StringView view) {
-        return JSValue::encode(JSBigInt::parseInt(globalObject, view));
-    }));
</del><ins>+    return throwVMTypeError(globalObject, scope, "Invalid argument type in ToBigInt operation"_s);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL callBigIntConstructor(JSGlobalObject* globalObject, CallFrame* callFrame)
</span><span class="lines">@@ -119,20 +111,22 @@
</span><span class="cx">     JSValue primitive = value.toPrimitive(globalObject);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="cx"> 
</span><del>-    if (primitive.isNumber()) {
-        if (!isSafeInteger(primitive))
-            return throwVMError(globalObject, scope, createRangeError(globalObject, "Not safe integer"_s));
-        
-        scope.release();
-        if (primitive.isInt32())
-            return JSValue::encode(JSBigInt::createFrom(vm, primitive.asInt32()));
</del><ins>+    if (primitive.isInt32()) {
+#if USE(BIGINT32)
+        return JSValue::encode(JSValue(JSValue::JSBigInt32, primitive.asInt32()));
+#else
+        return JSValue::encode(JSBigInt::createFrom(vm, primitive.asInt32()));
+#endif
+    }
</ins><span class="cx"> 
</span><del>-        if (primitive.isUInt32())
-            return JSValue::encode(JSBigInt::createFrom(vm, primitive.asUInt32()));
</del><ins>+    if (primitive.isDouble()) {
+        double number = primitive.asDouble();
+        if (trunc(number) != number || std::abs(number) > maxSafeInteger())
+            return throwVMError(globalObject, scope, createRangeError(globalObject, "Not a safe integer"_s));
</ins><span class="cx"> 
</span><del>-        return JSValue::encode(JSBigInt::createFrom(vm, static_cast<int64_t>(primitive.asDouble())));
</del><ins>+        return JSValue::encode(JSBigInt::makeHeapBigIntOrBigInt32(vm, static_cast<int64_t>(primitive.asDouble())));
</ins><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     EncodedJSValue result = toBigInt(globalObject, primitive);
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="cx">     return result;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeBigIntObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/BigIntObject.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/BigIntObject.cpp     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/BigIntObject.cpp        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2017 Caio Lima <ticaiolima@gmail.com>.
</span><del>- * Copyright (C) 2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -37,7 +37,7 @@
</span><span class="cx"> const ClassInfo BigIntObject::s_info = { "BigInt", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(BigIntObject) };
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-BigIntObject* BigIntObject::create(VM& vm, JSGlobalObject* globalObject, JSBigInt* bigInt)
</del><ins>+BigIntObject* BigIntObject::create(VM& vm, JSGlobalObject* globalObject, JSValue bigInt)
</ins><span class="cx"> {
</span><span class="cx">     BigIntObject* object = new (NotNull, allocateCell<BigIntObject>(vm.heap)) BigIntObject(vm, globalObject->bigIntObjectStructure());
</span><span class="cx">     object->finishCreation(vm, bigInt);
</span><span class="lines">@@ -49,7 +49,7 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void BigIntObject::finishCreation(VM& vm, JSBigInt* bigInt)
</del><ins>+void BigIntObject::finishCreation(VM& vm, JSValue bigInt)
</ins><span class="cx"> {
</span><span class="cx">     Base::finishCreation(vm);
</span><span class="cx">     ASSERT(inherits(vm, info()));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeBigIntObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/BigIntObject.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/BigIntObject.h       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/BigIntObject.h  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2017 Caio Lima <ticaiolima@gmail.com>.
</span><del>- * Copyright (C) 2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -26,7 +26,6 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><del>-#include "JSBigInt.h"
</del><span class="cx"> #include "JSWrapperObject.h"
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -41,11 +40,11 @@
</span><span class="cx">         return vm.bigIntObjectSpace<mode>();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    static BigIntObject* create(VM&, JSGlobalObject*, JSBigInt*);
</del><ins>+    static BigIntObject* create(VM&, JSGlobalObject*, JSValue);
</ins><span class="cx"> 
</span><span class="cx">     DECLARE_EXPORT_INFO;
</span><span class="cx"> 
</span><del>-    JSBigInt* internalValue() const { return asBigInt(JSWrapperObject::internalValue()); }
</del><ins>+    JSValue internalValue() const { return JSWrapperObject::internalValue(); }
</ins><span class="cx"> 
</span><span class="cx">     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
</span><span class="cx">     {
</span><span class="lines">@@ -57,7 +56,7 @@
</span><span class="cx">     static String toStringName(const JSObject*, JSGlobalObject*);
</span><span class="cx"> 
</span><span class="cx"> protected:
</span><del>-    JS_EXPORT_PRIVATE void finishCreation(VM&, JSBigInt*);
</del><ins>+    JS_EXPORT_PRIVATE void finishCreation(VM&, JSValue);
</ins><span class="cx">     JS_EXPORT_PRIVATE BigIntObject(VM&, Structure*);
</span><span class="cx"> };
</span><span class="cx"> static_assert(sizeof(BigIntObject) == sizeof(JSWrapperObject));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeBigIntPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/BigIntPrototype.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/BigIntPrototype.cpp  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/BigIntPrototype.cpp     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -81,12 +81,24 @@
</span><span class="cx"> 
</span><span class="cx"> static ALWAYS_INLINE JSBigInt* toThisBigIntValue(VM& vm, JSValue thisValue)
</span><span class="cx"> {
</span><ins>+#if USE(BIGINT32)
+    // FIXME: heap-allocating all big ints is inneficient, but re-implementing toString for small BigInts is enough work that I'm deferring it to a later patch.
+    if (thisValue.isBigInt32())
+        return JSBigInt::createFrom(vm, thisValue.bigInt32AsInt32());
+#endif
+
</ins><span class="cx">     if (thisValue.isCell()) {
</span><span class="cx">         if (JSBigInt* bigInt = jsDynamicCast<JSBigInt*>(vm, thisValue.asCell()))
</span><span class="cx">             return bigInt;
</span><del>-        
-        if (BigIntObject* bigIntObject = jsDynamicCast<BigIntObject*>(vm, thisValue.asCell()))
-            return bigIntObject->internalValue();
</del><ins>+
+        if (BigIntObject* bigIntObject = jsDynamicCast<BigIntObject*>(vm, thisValue.asCell())) {
+            JSValue bigInt = bigIntObject->internalValue();
+#if USE(BIGINT32)
+            if (bigInt.isBigInt32())
+                return JSBigInt::createFrom(vm, bigInt.bigInt32AsInt32());
+#endif
+            return bigInt.asHeapBigInt();
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return nullptr;
</span><span class="lines">@@ -116,6 +128,7 @@
</span><span class="cx">     return JSValue::encode(jsNontrivialString(vm, resultString));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// FIXME: this function should introduce the right separators for thousands and similar things.
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL bigIntProtoFuncToLocaleString(JSGlobalObject* globalObject, CallFrame* callFrame)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCommonSlowPathscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -69,7 +69,6 @@
</span><span class="cx"> #include "ThunkGenerators.h"
</span><span class="cx"> #include "TypeProfilerLog.h"
</span><span class="cx"> #include <wtf/StringPrintStream.h>
</span><del>-#include <wtf/Variant.h>
</del><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -473,13 +472,8 @@
</span><span class="cx">     BEGIN();
</span><span class="cx">     auto bytecode = pc->as<OpInc>();
</span><span class="cx">     JSValue argument = GET_C(bytecode.m_srcDst).jsValue();
</span><del>-    Variant<JSBigInt*, double> resultVariant = argument.toNumeric(globalObject);
</del><ins>+    JSValue result = jsInc(globalObject, argument);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    JSValue result;
-    if (WTF::holds_alternative<JSBigInt*>(resultVariant))
-        result = JSBigInt::inc(globalObject, WTF::get<JSBigInt*>(resultVariant));
-    else
-        result = jsNumber(WTF::get<double>(resultVariant) + 1);
</del><span class="cx">     RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, result, { });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -488,13 +482,8 @@
</span><span class="cx">     BEGIN();
</span><span class="cx">     auto bytecode = pc->as<OpDec>();
</span><span class="cx">     JSValue argument = GET_C(bytecode.m_srcDst).jsValue();
</span><del>-    Variant<JSBigInt*, double> resultVariant = argument.toNumeric(globalObject);
</del><ins>+    JSValue result = jsDec(globalObject, argument);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    JSValue result;
-    if (WTF::holds_alternative<JSBigInt*>(resultVariant))
-        result = JSBigInt::dec(globalObject, WTF::get<JSBigInt*>(resultVariant));
-    else
-        result = jsNumber(WTF::get<double>(resultVariant) - 1);
</del><span class="cx">     RETURN_WITH_PROFILING_CUSTOM(bytecode.m_srcDst, result, { });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -511,7 +500,15 @@
</span><span class="cx">     UnaryArithProfile& profile = metadata.m_arithProfile;
</span><span class="cx">     profile.observeArg(operand);
</span><span class="cx">     ASSERT(result.isNumber() || result.isBigInt());
</span><del>-    if (result.isNumber()) {
</del><ins>+
+    if (result.isHeapBigInt())
+        profile.setObservedHeapBigInt();
+#if USE(BIGINT32)
+    else if (result.isBigInt32())
+        profile.setObservedBigInt32();
+#endif
+    else {
+        ASSERT(result.isNumber());
</ins><span class="cx">         if (!result.isInt32()) {
</span><span class="cx">             if (operand.isInt32())
</span><span class="cx">                 profile.setObservedInt32Overflow();
</span><span class="lines">@@ -531,10 +528,7 @@
</span><span class="cx">                     profile.setObservedInt52Overflow();
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-    } else if (result.isBigInt())
-        profile.setObservedBigInt();
-    else
-        profile.setObservedNonNumeric();
</del><ins>+    }
</ins><span class="cx"> }
</span><span class="cx"> #else
</span><span class="cx"> static void updateArithProfileForUnaryArithOp(OpNegate::Metadata&, JSValue, JSValue) { }
</span><span class="lines">@@ -549,8 +543,21 @@
</span><span class="cx">     JSValue primValue = operand.toPrimitive(globalObject, PreferNumber);
</span><span class="cx">     CHECK_EXCEPTION();
</span><span class="cx"> 
</span><del>-    if (primValue.isBigInt()) {
-        JSBigInt* result = JSBigInt::unaryMinus(vm, asBigInt(primValue));
</del><ins>+#if USE(BIGINT32)
+    if (primValue.isBigInt32()) {
+        int32_t value = primValue.bigInt32AsInt32();
+        if (value != INT_MIN) {
+            auto result = JSValue(JSValue::JSBigInt32, -value);
+            RETURN_WITH_PROFILING(result, {
+                updateArithProfileForUnaryArithOp(metadata, result, operand);
+            });
+        } else
+            primValue = JSBigInt::createFrom(vm, value);
+    }
+#endif
+
+    if (primValue.isHeapBigInt()) {
+        JSBigInt* result = JSBigInt::unaryMinus(vm, primValue.asHeapBigInt());
</ins><span class="cx">         RETURN_WITH_PROFILING(result, {
</span><span class="cx">             updateArithProfileForUnaryArithOp(metadata, result, operand);
</span><span class="cx">         });
</span><span class="lines">@@ -588,8 +595,12 @@
</span><span class="cx">                     profile.setObservedInt52Overflow();
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-    } else if (result.isBigInt())
-        profile.setObservedBigInt();
</del><ins>+    } else if (result.isHeapBigInt())
+        profile.setObservedHeapBigInt();
+#if USE(BIGINT32)
+    else if (result.isBigInt32())
+        profile.setObservedBigInt32();
+#endif
</ins><span class="cx">     else 
</span><span class="cx">         profile.setObservedNonNumeric();
</span><span class="cx"> }
</span><span class="lines">@@ -611,13 +622,8 @@
</span><span class="cx">     BEGIN();
</span><span class="cx">     auto bytecode = pc->as<OpToNumeric>();
</span><span class="cx">     JSValue argument = GET_C(bytecode.m_operand).jsValue();
</span><del>-    Variant<JSBigInt*, double> resultVariant = argument.toNumeric(globalObject);
</del><ins>+    JSValue result = argument.toNumeric(globalObject);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    JSValue result;
-    if (WTF::holds_alternative<JSBigInt*>(resultVariant))
-        result = WTF::get<JSBigInt*>(resultVariant);
-    else
-        result = jsNumber(WTF::get<double>(resultVariant));
</del><span class="cx">     RETURN_PROFILED(result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -653,7 +659,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // The following arithmetic and bitwise operations need to be sure to run
</span><del>-// toNumber() on their operands in order.  (A call to toNumber() is idempotent
</del><ins>+// toNumeric/toBigIntOrInt32() on their operands in order.  (A call to these is idempotent
</ins><span class="cx"> // if an exception is already set on the CallFrame.)
</span><span class="cx"> 
</span><span class="cx"> SLOW_PATH_DECL(slow_path_mul)
</span><span class="lines">@@ -675,24 +681,8 @@
</span><span class="cx">     auto bytecode = pc->as<OpSub>();
</span><span class="cx">     JSValue left = GET_C(bytecode.m_lhs).jsValue();
</span><span class="cx">     JSValue right = GET_C(bytecode.m_rhs).jsValue();
</span><del>-    auto leftNumeric = left.toNumeric(globalObject);
</del><ins>+    JSValue result = jsSub(globalObject, left, right);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    auto rightNumeric = right.toNumeric(globalObject);
-    CHECK_EXCEPTION();
-
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::sub(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-            CHECK_EXCEPTION();
-            RETURN_WITH_PROFILING(result, {
-                updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, left, right);
-            });
-        }
-
-        THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in subtraction."));
-    }
-
-    JSValue result = jsNumber(WTF::get<double>(leftNumeric) - WTF::get<double>(rightNumeric));
</del><span class="cx">     RETURN_WITH_PROFILING(result, {
</span><span class="cx">         updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, left, right);
</span><span class="cx">     });
</span><span class="lines">@@ -704,26 +694,8 @@
</span><span class="cx">     auto bytecode = pc->as<OpDiv>();
</span><span class="cx">     JSValue left = GET_C(bytecode.m_lhs).jsValue();
</span><span class="cx">     JSValue right = GET_C(bytecode.m_rhs).jsValue();
</span><del>-    auto leftNumeric = left.toNumeric(globalObject);
</del><ins>+    JSValue result = jsDiv(globalObject, left, right);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    auto rightNumeric = right.toNumeric(globalObject);
-    CHECK_EXCEPTION();
-
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::divide(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-            CHECK_EXCEPTION();
-            RETURN_WITH_PROFILING(result, {
-                updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, left, right);
-            });
-        }
-
-        THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in division."));
-    }
-
-    double a = WTF::get<double>(leftNumeric);
-    double b = WTF::get<double>(rightNumeric);
-    JSValue result = jsNumber(a / b);
</del><span class="cx">     RETURN_WITH_PROFILING(result, {
</span><span class="cx">         updateArithProfileForBinaryArithOp(globalObject, codeBlock, pc, result, left, right);
</span><span class="cx">     });
</span><span class="lines">@@ -735,24 +707,9 @@
</span><span class="cx">     auto bytecode = pc->as<OpMod>();
</span><span class="cx">     JSValue left = GET_C(bytecode.m_lhs).jsValue();
</span><span class="cx">     JSValue right = GET_C(bytecode.m_rhs).jsValue();
</span><del>-    auto leftNumeric = left.toNumeric(globalObject);
</del><ins>+    JSValue result = jsRemainder(globalObject, left, right);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    auto rightNumeric = right.toNumeric(globalObject);
-    CHECK_EXCEPTION();
-    
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::remainder(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-            CHECK_EXCEPTION();
-            RETURN(result);
-        }
-
-        THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in remainder operation."));
-    }
-    
-    double a = WTF::get<double>(leftNumeric);
-    double b = WTF::get<double>(rightNumeric);
-    RETURN(jsNumber(jsMod(a, b)));
</del><ins>+    RETURN(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SLOW_PATH_DECL(slow_path_pow)
</span><span class="lines">@@ -761,25 +718,9 @@
</span><span class="cx">     auto bytecode = pc->as<OpPow>();
</span><span class="cx">     JSValue left = GET_C(bytecode.m_lhs).jsValue();
</span><span class="cx">     JSValue right = GET_C(bytecode.m_rhs).jsValue();
</span><del>-    auto leftNumeric = left.toNumeric(globalObject);
</del><ins>+    JSValue result = jsPow(globalObject, left, right);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    auto rightNumeric = right.toNumeric(globalObject);
-    CHECK_EXCEPTION();
-
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::exponentiate(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-            CHECK_EXCEPTION();
-            RETURN(result);
-        }
-
-        THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in exponentiation operation."));
-    }
-    
-    double a = WTF::get<double>(leftNumeric);
-    double b = WTF::get<double>(rightNumeric);
-
-    RETURN(jsNumber(operationMathPow(a, b)));
</del><ins>+    RETURN(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SLOW_PATH_DECL(slow_path_lshift)
</span><span class="lines">@@ -788,22 +729,10 @@
</span><span class="cx">     auto bytecode = pc->as<OpLshift>();
</span><span class="cx">     JSValue left = GET_C(bytecode.m_lhs).jsValue();
</span><span class="cx">     JSValue right = GET_C(bytecode.m_rhs).jsValue();
</span><del>-    auto leftNumeric = left.toBigIntOrInt32(globalObject);
</del><ins>+
+    JSValue result = jsLShift(globalObject, left, right);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    auto rightNumeric = right.toBigIntOrInt32(globalObject);
-    CHECK_EXCEPTION();
-
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::leftShift(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-            CHECK_EXCEPTION();
-            RETURN_PROFILED(result);
-        }
-
-        THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in left shift operation."));
-    }
-
-    RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) << (WTF::get<int32_t>(rightNumeric) & 31)));
</del><ins>+    RETURN_PROFILED(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SLOW_PATH_DECL(slow_path_rshift)
</span><span class="lines">@@ -812,22 +741,10 @@
</span><span class="cx">     auto bytecode = pc->as<OpRshift>();
</span><span class="cx">     JSValue left = GET_C(bytecode.m_lhs).jsValue();
</span><span class="cx">     JSValue right = GET_C(bytecode.m_rhs).jsValue();
</span><del>-    auto leftNumeric = left.toBigIntOrInt32(globalObject);
</del><ins>+
+    JSValue result = jsRShift(globalObject, left, right);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    auto rightNumeric = right.toBigIntOrInt32(globalObject);
-    CHECK_EXCEPTION();
-
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::signedRightShift(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-            CHECK_EXCEPTION();
-            RETURN_PROFILED(result);
-        }
-
-        THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in signed right shift operation."_s));
-    }
-
-    RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) >> (WTF::get<int32_t>(rightNumeric) & 31)));
</del><ins>+    RETURN_PROFILED(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SLOW_PATH_DECL(slow_path_urshift)
</span><span class="lines">@@ -853,16 +770,11 @@
</span><span class="cx"> {
</span><span class="cx">     BEGIN();
</span><span class="cx">     auto bytecode = pc->as<OpBitnot>();
</span><del>-    auto operandNumeric = GET_C(bytecode.m_operand).jsValue().toBigIntOrInt32(globalObject);
</del><ins>+    auto operand = GET_C(bytecode.m_operand).jsValue();
+
+    auto result = jsBitwiseNot(globalObject, operand);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-
-    if (WTF::holds_alternative<JSBigInt*>(operandNumeric)) {
-        JSBigInt* result = JSBigInt::bitwiseNot(globalObject, WTF::get<JSBigInt*>(operandNumeric));
-        CHECK_EXCEPTION();
-        RETURN_PROFILED(result);
-    }
-
-    RETURN_PROFILED(jsNumber(~WTF::get<int32_t>(operandNumeric)));
</del><ins>+    RETURN_PROFILED(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SLOW_PATH_DECL(slow_path_bitand)
</span><span class="lines">@@ -869,21 +781,12 @@
</span><span class="cx"> {
</span><span class="cx">     BEGIN();
</span><span class="cx">     auto bytecode = pc->as<OpBitand>();
</span><del>-    auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(globalObject);
</del><ins>+    auto left = GET_C(bytecode.m_lhs).jsValue();
+    auto right = GET_C(bytecode.m_rhs).jsValue();
+
+    JSValue result = jsBitwiseAnd(globalObject, left, right);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(globalObject);
-    CHECK_EXCEPTION();
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::bitwiseAnd(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-            CHECK_EXCEPTION();
-            RETURN_PROFILED(result);
-        }
-
-        THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in bitwise 'and' operation."));
-    }
-
-    RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) & WTF::get<int32_t>(rightNumeric)));
</del><ins>+    RETURN_PROFILED(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SLOW_PATH_DECL(slow_path_bitor)
</span><span class="lines">@@ -890,21 +793,12 @@
</span><span class="cx"> {
</span><span class="cx">     BEGIN();
</span><span class="cx">     auto bytecode = pc->as<OpBitor>();
</span><del>-    auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(globalObject);
</del><ins>+    auto left = GET_C(bytecode.m_lhs).jsValue();
+    auto right = GET_C(bytecode.m_rhs).jsValue();
+
+    JSValue result = jsBitwiseOr(globalObject, left, right);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(globalObject);
-    CHECK_EXCEPTION();
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::bitwiseOr(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-            CHECK_EXCEPTION();
-            RETURN_PROFILED(result);
-        }
-
-        THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in bitwise 'or' operation."));
-    }
-
-    RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) | WTF::get<int32_t>(rightNumeric)));
</del><ins>+    RETURN_PROFILED(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SLOW_PATH_DECL(slow_path_bitxor)
</span><span class="lines">@@ -911,21 +805,12 @@
</span><span class="cx"> {
</span><span class="cx">     BEGIN();
</span><span class="cx">     auto bytecode = pc->as<OpBitxor>();
</span><del>-    auto leftNumeric = GET_C(bytecode.m_lhs).jsValue().toBigIntOrInt32(globalObject);
</del><ins>+    auto left = GET_C(bytecode.m_lhs).jsValue();
+    auto right = GET_C(bytecode.m_rhs).jsValue();
+
+    JSValue result = jsBitwiseXor(globalObject, left, right);
</ins><span class="cx">     CHECK_EXCEPTION();
</span><del>-    auto rightNumeric = GET_C(bytecode.m_rhs).jsValue().toBigIntOrInt32(globalObject);
-    CHECK_EXCEPTION();
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            JSBigInt* result = JSBigInt::bitwiseXor(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-            CHECK_EXCEPTION();
-            RETURN_PROFILED(result);
-        }
-
-        THROW(createTypeError(globalObject, "Invalid mix of BigInt and other type in bitwise 'xor' operation."));
-    }
-
-    RETURN_PROFILED(jsNumber(WTF::get<int32_t>(leftNumeric) ^ WTF::get<int32_t>(rightNumeric)));
</del><ins>+    RETURN_PROFILED(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SLOW_PATH_DECL(slow_path_typeof)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeIntlNumberFormatPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -87,12 +87,25 @@
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="cx">     auto* numberFormat = jsCast<IntlNumberFormat*>(callFrame->thisValue());
</span><span class="cx"> 
</span><del>-    auto variant = callFrame->argument(0).toNumeric(globalObject);
</del><ins>+    JSValue bigIntOrNumber = callFrame->argument(0).toNumeric(globalObject);
</ins><span class="cx">     RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="cx"> 
</span><del>-    RELEASE_AND_RETURN(scope, JSValue::encode(switchOn(variant, [&](auto&& value) {
-        return numberFormat->format(globalObject, value);
-    })));
</del><ins>+    scope.release();
+    if (bigIntOrNumber.isNumber()) {
+        double value = bigIntOrNumber.asNumber();
+        return JSValue::encode(numberFormat->format(globalObject, value));
+    }
+
+#if USE(BIGINT32)
+    if (bigIntOrNumber.isBigInt32()) {
+        JSBigInt* value = JSBigInt::createFrom(vm, bigIntOrNumber.bigInt32AsInt32());
+        return JSValue::encode(numberFormat->format(globalObject, value));
+    }
+#endif
+
+    ASSERT(bigIntOrNumber.isHeapBigInt());
+    JSBigInt* value = bigIntOrNumber.asHeapBigInt();
+    return JSValue::encode(numberFormat->format(globalObject, value));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL IntlNumberFormatPrototypeGetterFormat(JSGlobalObject* globalObject, CallFrame* callFrame)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSBigIntcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp 2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp    2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2017 Caio Lima <ticaiolima@gmail.com>
</span><del>- * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2017-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -80,7 +80,7 @@
</span><span class="cx"> 
</span><span class="cx"> Structure* JSBigInt::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
</span><span class="cx"> {
</span><del>-    return Structure::create(vm, globalObject, prototype, TypeInfo(BigIntType, StructureFlags), info());
</del><ins>+    return Structure::create(vm, globalObject, prototype, TypeInfo(HeapBigIntType, StructureFlags), info());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSBigInt* JSBigInt::createZero(VM& vm)
</span><span class="lines">@@ -142,8 +142,10 @@
</span><span class="cx"> {
</span><span class="cx">     if (!value)
</span><span class="cx">         return createZero(vm);
</span><del>-    
-    if (sizeof(Digit) == 8) {
</del><ins>+
+    // This path is not just an optimization: because we do not call rightTrim at the end of this function,
+    // it would be a bug to create a BigInt with length=2 in this case.
+    if (sizeof(Digit) == 8 || (value <= INT_MAX && value >= INT_MIN)) {
</ins><span class="cx">         JSBigInt* bigInt = createWithLengthUnchecked(vm, 1);
</span><span class="cx">         if (value < 0) {
</span><span class="cx">             bigInt->setDigit(0, static_cast<Digit>(static_cast<uint64_t>(-(value + 1)) + 1));
</span><span class="lines">@@ -188,27 +190,14 @@
</span><span class="cx">     return const_cast<JSBigInt*>(this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Optional<uint8_t> JSBigInt::singleDigitValueForString()
</del><ins>+JSValue JSBigInt::parseInt(JSGlobalObject* globalObject, StringView s, ErrorParseMode parserMode)
</ins><span class="cx"> {
</span><del>-    if (isZero())
-        return 0;
-    
-    if (length() == 1 && !sign()) {
-        Digit rDigit = digit(0);
-        if (rDigit <= 9)
-            return static_cast<uint8_t>(rDigit);
-    }
-    return { };
-}
-
-JSBigInt* JSBigInt::parseInt(JSGlobalObject* globalObject, StringView s, ErrorParseMode parserMode)
-{
</del><span class="cx">     if (s.is8Bit())
</span><span class="cx">         return parseInt(globalObject, s.characters8(), s.length(), parserMode);
</span><span class="cx">     return parseInt(globalObject, s.characters16(), s.length(), parserMode);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSBigInt* JSBigInt::parseInt(JSGlobalObject* globalObject, VM& vm, StringView s, uint8_t radix, ErrorParseMode parserMode, ParseIntSign sign)
</del><ins>+JSValue JSBigInt::parseInt(JSGlobalObject* globalObject, VM& vm, StringView s, uint8_t radix, ErrorParseMode parserMode, ParseIntSign sign)
</ins><span class="cx"> {
</span><span class="cx">     if (s.is8Bit())
</span><span class="cx">         return parseInt(globalObject, vm, s.characters8(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString);
</span><span class="lines">@@ -215,7 +204,7 @@
</span><span class="cx">     return parseInt(globalObject, vm, s.characters16(), s.length(), 0, radix, parserMode, sign, ParseIntMode::DisallowEmptyString);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-JSBigInt* JSBigInt::stringToBigInt(JSGlobalObject* globalObject, StringView s)
</del><ins>+JSValue JSBigInt::stringToBigInt(JSGlobalObject* globalObject, StringView s)
</ins><span class="cx"> {
</span><span class="cx">     return parseInt(globalObject, s, ErrorParseMode::IgnoreExceptions);
</span><span class="cx"> }
</span><span class="lines">@@ -454,16 +443,23 @@
</span><span class="cx"> 
</span><span class="cx"> JSBigInt* JSBigInt::inc(JSGlobalObject* globalObject, JSBigInt* x)
</span><span class="cx"> {
</span><del>-    // FIXME: we can probably do something a fair bit more efficient here
-    VM& vm = globalObject->vm();
-    return add(globalObject, x, vm.bigIntConstantOne.get());
</del><ins>+    if (!x->sign())
+        return absoluteAddOne(globalObject, x, SignOption::Unsigned);
+    JSBigInt* result = absoluteSubOne(globalObject, x, x->length());
+    result->setSign(true);
+    return result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSBigInt* JSBigInt::dec(JSGlobalObject* globalObject, JSBigInt* x)
</span><span class="cx"> {
</span><del>-    // FIXME: we can probably do something a fair bit more efficient here
-    VM& vm = globalObject->vm();
-    return sub(globalObject, x, vm.bigIntConstantOne.get());
</del><ins>+    if (x->isZero()) {
+        JSBigInt* result = createFrom(globalObject->vm(), 1);
+        result->setSign(true);
+        return result;
+    }
+    if (!x->sign())
+        return absoluteSubOne(globalObject, x, x->length());
+    return absoluteAddOne(globalObject, x, SignOption::Signed);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSBigInt* JSBigInt::add(JSGlobalObject* globalObject, JSBigInt* x, JSBigInt* y)
</span><span class="lines">@@ -532,7 +528,7 @@
</span><span class="cx">     if (x->sign())
</span><span class="cx">         std::swap(x, y);
</span><span class="cx">     
</span><del>-    // x & (-y) == x & ~(y-1) == x & ~(y-1)
</del><ins>+    // x & (-y) == x & ~(y-1)
</ins><span class="cx">     JSBigInt* y1 = absoluteSubOne(globalObject, y, y->length());
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">     return absoluteAndNot(vm, x, y1);
</span><span class="lines">@@ -1644,7 +1640,7 @@
</span><span class="cx"> String JSBigInt::toStringGeneric(VM& vm, JSGlobalObject* globalObject, JSBigInt* x, unsigned radix)
</span><span class="cx"> {
</span><span class="cx">     // FIXME: [JSC] Revisit usage of Vector into JSBigInt::toString
</span><del>-    // https://bugs.webkit.org/show_bug.cgi?id=18067
</del><ins>+    // https://bugs.webkit.org/show_bug.cgi?id=180671
</ins><span class="cx">     Vector<LChar> resultString;
</span><span class="cx"> 
</span><span class="cx">     ASSERT(radix >= 2 && radix <= 36);
</span><span class="lines">@@ -1802,7 +1798,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template <typename CharType>
</span><del>-JSBigInt* JSBigInt::parseInt(JSGlobalObject* globalObject, CharType*  data, unsigned length, ErrorParseMode errorParseMode)
</del><ins>+JSValue JSBigInt::parseInt(JSGlobalObject* globalObject, CharType*  data, unsigned length, ErrorParseMode errorParseMode)
</ins><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx"> 
</span><span class="lines">@@ -1810,7 +1806,7 @@
</span><span class="cx">     while (p < length && isStrWhiteSpace(data[p]))
</span><span class="cx">         ++p;
</span><span class="cx"> 
</span><del>-    // Check Radix from frist characters
</del><ins>+    // Check Radix from first characters
</ins><span class="cx">     if (static_cast<unsigned>(p) + 1 < static_cast<unsigned>(length) && data[p] == '0') {
</span><span class="cx">         if (isASCIIAlphaCaselessEqual(data[p + 1], 'b'))
</span><span class="cx">             return parseInt(globalObject, vm, data, length, p + 2, 2, errorParseMode, ParseIntSign::Unsigned, ParseIntMode::DisallowEmptyString);
</span><span class="lines">@@ -1824,24 +1820,18 @@
</span><span class="cx"> 
</span><span class="cx">     ParseIntSign sign = ParseIntSign::Unsigned;
</span><span class="cx">     if (p < length) {
</span><del>-        if (data[p] == '+')
-            ++p;
-        else if (data[p] == '-') {
</del><ins>+        if (data[p] == '-') {
</ins><span class="cx">             sign = ParseIntSign::Signed;
</span><span class="cx">             ++p;
</span><del>-        }
</del><ins>+        } else if (data[p] == '+')
+            ++p;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    JSBigInt* result = parseInt(globalObject, vm, data, length, p, 10, errorParseMode, sign);
-
-    if (result && !result->isZero())
-        result->setSign(sign == ParseIntSign::Signed);
-
-    return result;
</del><ins>+    return parseInt(globalObject, vm, data, length, p, 10, errorParseMode, sign);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template <typename CharType>
</span><del>-JSBigInt* JSBigInt::parseInt(JSGlobalObject* globalObject, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode errorParseMode, ParseIntSign sign, ParseIntMode parseMode)
</del><ins>+JSValue JSBigInt::parseInt(JSGlobalObject* globalObject, VM& vm, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode errorParseMode, ParseIntSign sign, ParseIntMode parseMode)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(length >= 0);
</span><span class="cx">     unsigned p = startIndex;
</span><span class="lines">@@ -1852,7 +1842,7 @@
</span><span class="cx">         ASSERT(globalObject);
</span><span class="cx">         if (errorParseMode == ErrorParseMode::ThrowExceptions)
</span><span class="cx">             throwVMError(globalObject, scope, createSyntaxError(globalObject, "Failed to parse String to BigInt"));
</span><del>-        return nullptr;
</del><ins>+        return JSValue();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Skipping leading zeros
</span><span class="lines">@@ -1866,44 +1856,84 @@
</span><span class="cx"> 
</span><span class="cx">     length = endIndex + 1;
</span><span class="cx"> 
</span><del>-    if (p == length)
</del><ins>+    if (p == length) {
+#if USE(BIGINT32)
+        return JSValue(JSValue::JSBigInt32, 0);
+#else
</ins><span class="cx">         return createZero(vm);
</span><ins>+#endif
+    }
</ins><span class="cx"> 
</span><del>-    unsigned limit0 = '0' + (radix < 10 ? radix : 10);
-    unsigned limita = 'a' + (radix - 10);
-    unsigned limitA = 'A' + (radix - 10);
</del><ins>+    // The idea is to pick the largest number such that radix ** lengthLimitForBigInt32 <= INT32_MAX
+    unsigned lengthLimitForBigInt32;
+    switch (radix) {
+    case 2:
+        lengthLimitForBigInt32 = 30;
+        break;
+    case 8:
+        lengthLimitForBigInt32 = 10;
+        break;
+    case 10:
+        lengthLimitForBigInt32 = 9;
+        break;
+    case 16:
+        lengthLimitForBigInt32 = 7;
+        break;
+    default:
+        lengthLimitForBigInt32 = 1;
+        break;
+    }
</ins><span class="cx"> 
</span><del>-    JSBigInt* result = allocateFor(globalObject, vm, radix, length - p);
-    RETURN_IF_EXCEPTION(scope, nullptr);
-    // result can still be null if we don't have access to global object, as allocateFor cannot throw an exception in that case.
-    if (!result)
-        return nullptr;
</del><ins>+    JSBigInt* heapResult = nullptr;
</ins><span class="cx"> 
</span><del>-    result->initialize(InitializationType::WithZero);
</del><ins>+    unsigned limit0 = '0' + (radix < 10 ? radix : 10);
+    unsigned limita = 'a' + (static_cast<int32_t>(radix) - 10);
+    unsigned limitA = 'A' + (static_cast<int32_t>(radix) - 10);
+    unsigned initialLength = length - p;
+    while (p < length) {
+        int32_t digit = 0;
+        Checked<int32_t, CrashOnOverflow> multiplier = 1;
+        for (unsigned i = 0; i < lengthLimitForBigInt32 && p < length ; ++i, ++p) {
+            digit *= radix;
+            multiplier *= radix;
+            if (data[p] >= '0' && data[p] < limit0)
+                digit += data[p] - '0';
+            else if (data[p] >= 'a' && data[p] < limita)
+                digit += data[p] - 'a' + 10;
+            else if (data[p] >= 'A' && data[p] < limitA)
+                digit += data[p] - 'A' + 10;
+            else {
+                if (errorParseMode == ErrorParseMode::ThrowExceptions) {
+                    ASSERT(globalObject);
+                    throwVMError(globalObject, scope, createSyntaxError(globalObject, "Failed to parse String to BigInt"));
+                }
+                return JSValue();
+            }
+        }
+        ASSERT(digit < multiplier.unsafeGet());
</ins><span class="cx"> 
</span><del>-    for (unsigned i = p; i < length; i++, p++) {
-        uint32_t digit;
-        if (data[i] >= '0' && data[i] < limit0)
-            digit = data[i] - '0';
-        else if (data[i] >= 'a' && data[i] < limita)
-            digit = data[i] - 'a' + 10;
-        else if (data[i] >= 'A' && data[i] < limitA)
-            digit = data[i] - 'A' + 10;
-        else
-            break;
-
-        result->inplaceMultiplyAdd(static_cast<Digit>(radix), static_cast<Digit>(digit));
</del><ins>+        if (!heapResult) {
+            if (p == length) {
+                if (sign == ParseIntSign::Signed)
+                    digit *= -1;
+#if USE(BIGINT32)
+                return JSValue(JSValue::JSBigInt32, digit);
+#else
+                return createFrom(vm, static_cast<int64_t>(digit));
+#endif
+            }
+            heapResult = allocateFor(globalObject, vm, radix, initialLength);
+            RETURN_IF_EXCEPTION(scope, JSValue());
+            // result can still be null if we don't have access to global object, as allocateFor cannot throw an exception in that case.
+            if (!heapResult)
+                return JSValue();
+            heapResult->initialize(InitializationType::WithZero);
+        }
+        heapResult->inplaceMultiplyAdd(static_cast<Digit>(multiplier.unsafeGet()), static_cast<Digit>(digit));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    result->setSign(sign == ParseIntSign::Signed ? true : false);
-    if (p == length)
-        return result->rightTrim(vm);
-
-    ASSERT(globalObject);
-    if (errorParseMode == ErrorParseMode::ThrowExceptions)
-        throwVMError(globalObject, scope, createSyntaxError(globalObject, "Failed to parse String to BigInt"));
-
-    return nullptr;
</del><ins>+    heapResult->setSign(sign == ParseIntSign::Signed);
+    return heapResult->rightTrim(vm);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline JSBigInt::Digit JSBigInt::digit(unsigned n)
</span><span class="lines">@@ -1927,18 +1957,20 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(numValue.isNumber());
</span><span class="cx">     
</span><del>-    if (numValue.isInt32()) {
-        int value = numValue.asInt32();
-        if (!value)
-            return this->isZero();
-
-        return (this->length() == 1) && (this->sign() == (value < 0)) && (this->digit(0) == static_cast<Digit>(std::abs(static_cast<int64_t>(value))));
-    }
</del><ins>+    if (numValue.isInt32())
+        return equalsToInt32(numValue.asInt32());
</ins><span class="cx">     
</span><span class="cx">     double value = numValue.asDouble();
</span><span class="cx">     return compareToDouble(this, value) == ComparisonResult::Equal;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool JSBigInt::equalsToInt32(int32_t value)
+{
+    if (!value)
+        return this->isZero();
+    return (this->length() == 1) && (this->sign() == (value < 0)) && (this->digit(0) == static_cast<Digit>(std::abs(static_cast<int64_t>(value))));
+}
+
</ins><span class="cx"> JSBigInt::ComparisonResult JSBigInt::compareToDouble(JSBigInt* x, double y)
</span><span class="cx"> {
</span><span class="cx">     // This algorithm expect that the double format is IEEE 754
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSBigInth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSBigInt.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSBigInt.h   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSBigInt.h      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2017 Caio Lima <ticaiolima@gmail.com>
</span><del>- * Copyright (C) 2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2019-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -82,6 +82,17 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned length() const { return m_length; }
</span><span class="cx"> 
</span><ins>+    static JSValue makeHeapBigIntOrBigInt32(VM& vm, int64_t value)
+    {
+#if USE(BIGINT32)
+        if (value <= INT_MAX && value >= INT_MIN)
+            return JSValue(JSValue::JSBigInt32, static_cast<int32_t>(value));
+#endif
+
+        auto ptr = JSBigInt::createFrom(vm, value);
+        return JSValue(static_cast<JSCell*>(ptr));
+    }
+
</ins><span class="cx">     enum class ErrorParseMode {
</span><span class="cx">         ThrowExceptions,
</span><span class="cx">         IgnoreExceptions
</span><span class="lines">@@ -90,13 +101,12 @@
</span><span class="cx">     enum class ParseIntMode { DisallowEmptyString, AllowEmptyString };
</span><span class="cx">     enum class ParseIntSign { Unsigned, Signed };
</span><span class="cx"> 
</span><del>-    static JSBigInt* parseInt(JSGlobalObject*, VM&, StringView, uint8_t radix, ErrorParseMode = ErrorParseMode::ThrowExceptions, ParseIntSign = ParseIntSign::Unsigned);
-    static JSBigInt* parseInt(JSGlobalObject*, StringView, ErrorParseMode = ErrorParseMode::ThrowExceptions);
-    static JSBigInt* stringToBigInt(JSGlobalObject*, StringView);
</del><ins>+    static JSValue parseInt(JSGlobalObject*, VM&, StringView, uint8_t radix, ErrorParseMode = ErrorParseMode::ThrowExceptions, ParseIntSign = ParseIntSign::Unsigned);
+    static JSValue parseInt(JSGlobalObject*, StringView, ErrorParseMode = ErrorParseMode::ThrowExceptions);
+    static JSValue stringToBigInt(JSGlobalObject*, StringView);
</ins><span class="cx"> 
</span><span class="cx">     static String tryGetString(VM&, JSBigInt*, unsigned radix);
</span><span class="cx"> 
</span><del>-    Optional<uint8_t> singleDigitValueForString();
</del><span class="cx">     String toString(JSGlobalObject*, unsigned radix);
</span><span class="cx">     
</span><span class="cx">     enum class ComparisonMode {
</span><span class="lines">@@ -113,6 +123,7 @@
</span><span class="cx">     
</span><span class="cx">     JS_EXPORT_PRIVATE static bool equals(JSBigInt*, JSBigInt*);
</span><span class="cx">     bool equalsToNumber(JSValue);
</span><ins>+    JS_EXPORT_PRIVATE bool equalsToInt32(int32_t);
</ins><span class="cx">     static ComparisonResult compare(JSBigInt* x, JSBigInt* y);
</span><span class="cx"> 
</span><span class="cx">     bool getPrimitiveNumber(JSGlobalObject*, double& number, JSValue& result) const;
</span><span class="lines">@@ -222,10 +233,10 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     template <typename CharType>
</span><del>-    static JSBigInt* parseInt(JSGlobalObject*, CharType*  data, unsigned length, ErrorParseMode);
</del><ins>+    static JSValue parseInt(JSGlobalObject*, CharType*  data, unsigned length, ErrorParseMode);
</ins><span class="cx"> 
</span><span class="cx">     template <typename CharType>
</span><del>-    static JSBigInt* parseInt(JSGlobalObject*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, ParseIntSign = ParseIntSign::Signed, ParseIntMode = ParseIntMode::AllowEmptyString);
</del><ins>+    static JSValue parseInt(JSGlobalObject*, VM&, CharType* data, unsigned length, unsigned startIndex, unsigned radix, ErrorParseMode, ParseIntSign = ParseIntSign::Signed, ParseIntMode = ParseIntMode::AllowEmptyString);
</ins><span class="cx"> 
</span><span class="cx">     static JSBigInt* allocateFor(JSGlobalObject*, VM&, unsigned radix, unsigned charcount);
</span><span class="cx"> 
</span><span class="lines">@@ -258,9 +269,9 @@
</span><span class="cx">     CagedUniquePtr<Gigacage::Primitive, Digit> m_data;
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-inline JSBigInt* asBigInt(JSValue value)
</del><ins>+inline JSBigInt* asHeapBigInt(JSValue value)
</ins><span class="cx"> {
</span><del>-    ASSERT(value.asCell()->isBigInt());
</del><ins>+    ASSERT(value.asCell()->isHeapBigInt());
</ins><span class="cx">     return jsCast<JSBigInt*>(value.asCell());
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCJSValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -23,6 +23,7 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "JSCJSValue.h"
</span><span class="cx"> 
</span><ins>+#include "BigIntObject.h"
</ins><span class="cx"> #include "BooleanConstructor.h"
</span><span class="cx"> #include "BooleanPrototype.h"
</span><span class="cx"> #include "CustomGetterSetter.h"
</span><span class="lines">@@ -68,9 +69,18 @@
</span><span class="cx"> 
</span><span class="cx"> double JSValue::toNumberSlowCase(JSGlobalObject* globalObject) const
</span><span class="cx"> {
</span><ins>+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
</ins><span class="cx">     ASSERT(!isInt32() && !isDouble());
</span><span class="cx">     if (isCell())
</span><del>-        return asCell()->toNumber(globalObject);
</del><ins>+        RELEASE_AND_RETURN(scope, asCell()->toNumber(globalObject));
+#if USE(BIGINT32)
+    if (isBigInt32()) {
+        throwTypeError(globalObject, scope, "Conversion from 'BigInt' to 'number' is not allowed."_s);
+        return 0.0;
+    }
+#endif
</ins><span class="cx">     if (isTrue())
</span><span class="cx">         return 1.0;
</span><span class="cx">     return isUndefined() ? PNaN : 0; // null and false both convert to 0.
</span><span class="lines">@@ -101,6 +111,10 @@
</span><span class="cx">         return constructNumber(globalObject, asValue());
</span><span class="cx">     if (isTrue() || isFalse())
</span><span class="cx">         return constructBooleanFromImmediateBoolean(globalObject, asValue());
</span><ins>+#if USE(BIGINT32)
+    if (isBigInt32())
+        return BigIntObject::create(vm, globalObject, *this);
+#endif
</ins><span class="cx"> 
</span><span class="cx">     ASSERT(isUndefinedOrNull());
</span><span class="cx">     throwException(globalObject, scope, createNotAnObjectError(globalObject, *this));
</span><span class="lines">@@ -118,6 +132,13 @@
</span><span class="cx">         return constructNumber(globalObject, asValue());
</span><span class="cx">     if (isTrue() || isFalse())
</span><span class="cx">         return constructBooleanFromImmediateBoolean(globalObject, asValue());
</span><ins>+#if USE(BIGINT32)
+    if (isBigInt32()) {
+        JSCell* heapBigInt = static_cast<JSCell*>(JSBigInt::createFrom(globalObject->vm(), bigInt32AsInt32()));
+        return heapBigInt->toObject(globalObject);
+    }
+#endif
+
</ins><span class="cx">     ASSERT(isUndefinedOrNull());
</span><span class="cx">     return globalObject->globalThis();
</span><span class="cx"> }
</span><span class="lines">@@ -130,7 +151,7 @@
</span><span class="cx">     if (isCell()) {
</span><span class="cx">         if (isString())
</span><span class="cx">             return globalObject->stringPrototype();
</span><del>-        if (isBigInt())
</del><ins>+        if (isHeapBigInt())
</ins><span class="cx">             return globalObject->bigIntPrototype();
</span><span class="cx">         ASSERT(isSymbol());
</span><span class="cx">         return globalObject->symbolPrototype();
</span><span class="lines">@@ -140,6 +161,10 @@
</span><span class="cx">         return globalObject->numberPrototype();
</span><span class="cx">     if (isBoolean())
</span><span class="cx">         return globalObject->booleanPrototype();
</span><ins>+#if USE(BIGINT32)
+    if (isBigInt32())
+        return globalObject->bigIntPrototype();
+#endif
</ins><span class="cx"> 
</span><span class="cx">     ASSERT(isUndefinedOrNull());
</span><span class="cx">     throwException(globalObject, scope, createNotAnObjectError(globalObject, *this));
</span><span class="lines">@@ -286,6 +311,8 @@
</span><span class="cx">             out.print("Symbol: ", RawPointer(asCell()));
</span><span class="cx">         else if (structure->classInfo()->isSubClassOf(Structure::info()))
</span><span class="cx">             out.print("Structure: ", inContext(*jsCast<Structure*>(asCell()), context));
</span><ins>+        else if (isHeapBigInt())
+            out.print("BigInt[heap-allocated]: addr=", RawPointer(asCell()));
</ins><span class="cx">         else if (structure->classInfo()->isSubClassOf(JSObject::info())) {
</span><span class="cx">             out.print("Object: ", RawPointer(asCell()));
</span><span class="cx">             out.print(" with butterfly ", RawPointer(asObject(asCell())->butterfly()));
</span><span class="lines">@@ -305,6 +332,10 @@
</span><span class="cx">         out.print("Null");
</span><span class="cx">     else if (isUndefined())
</span><span class="cx">         out.print("Undefined");
</span><ins>+#if USE(BIGINT32)
+    else if (isBigInt32())
+        out.printf("BigInt[inline]: %d", bigInt32AsInt32());
+#endif
</ins><span class="cx">     else
</span><span class="cx">         out.print("INVALID");
</span><span class="cx"> }
</span><span class="lines">@@ -347,6 +378,10 @@
</span><span class="cx">         out.print("Null");
</span><span class="cx">     else if (isUndefined())
</span><span class="cx">         out.print("Undefined");
</span><ins>+#if USE(BIGINT32)
+    else if (isBigInt32())
+        out.printf("BigInt[inline]: %d", bigInt32AsInt32());
+#endif
</ins><span class="cx">     else
</span><span class="cx">         out.print("INVALID");
</span><span class="cx"> }
</span><span class="lines">@@ -384,18 +419,27 @@
</span><span class="cx">         return vm.smallStrings.nullString();
</span><span class="cx">     if (isUndefined())
</span><span class="cx">         return vm.smallStrings.undefinedString();
</span><ins>+#if USE(BIGINT32)
+    if (isBigInt32()) {
+        auto integer = bigInt32AsInt32();
+        if (static_cast<unsigned>(integer) <= 9)
+            return vm.smallStrings.singleCharacterString(integer + '0');
+        return jsNontrivialString(vm, vm.numericStrings.add(integer));
+    }
+#endif
+    if (isHeapBigInt()) {
+        JSBigInt* bigInt = asHeapBigInt();
+        // FIXME: we should rather have two cases here: one-character string vs jsNonTrivialString for everything else.
+        auto string = bigInt->toString(globalObject, 10);
+        RETURN_IF_EXCEPTION(scope, errorValue());
+        JSString* returnString = JSString::create(vm, string.releaseImpl().releaseNonNull());
+        RETURN_IF_EXCEPTION(scope, errorValue());
+        return returnString;
+    }
</ins><span class="cx">     if (isSymbol()) {
</span><span class="cx">         throwTypeError(globalObject, scope, "Cannot convert a symbol to a string"_s);
</span><span class="cx">         return errorValue();
</span><span class="cx">     }
</span><del>-    if (isBigInt()) {
-        JSBigInt* bigInt = asBigInt(*this);
-        if (auto digit = bigInt->singleDigitValueForString())
-            return vm.smallStrings.singleCharacterString(*digit + '0');
-        JSString* returnString = jsNontrivialString(vm, bigInt->toString(globalObject, 10));
-        RETURN_IF_EXCEPTION(scope, errorValue());
-        return returnString;
-    }
</del><span class="cx"> 
</span><span class="cx">     ASSERT(isCell());
</span><span class="cx">     JSValue value = asCell()->toPrimitive(globalObject, PreferString);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCJSValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCJSValue.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCJSValue.h 2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSCJSValue.h    2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -177,6 +177,9 @@
</span><span class="cx">     enum JSTrueTag { JSTrue };
</span><span class="cx">     enum JSFalseTag { JSFalse };
</span><span class="cx">     enum JSCellTag { JSCellType };
</span><ins>+#if USE(BIGINT32)
+    enum JSBigInt32Tag { JSBigInt32 };
+#endif
</ins><span class="cx">     enum EncodeAsDoubleTag { EncodeAsDouble };
</span><span class="cx"> 
</span><span class="cx">     JSValue();
</span><span class="lines">@@ -186,6 +189,9 @@
</span><span class="cx">     JSValue(JSFalseTag);
</span><span class="cx">     JSValue(JSCell* ptr);
</span><span class="cx">     JSValue(const JSCell* ptr);
</span><ins>+#if USE(BIGINT32)
+    JSValue(JSBigInt32Tag, int32_t);
+#endif
</ins><span class="cx"> 
</span><span class="cx">     // Numbers
</span><span class="cx">     JSValue(EncodeAsDoubleTag, double);
</span><span class="lines">@@ -219,6 +225,9 @@
</span><span class="cx">     double asDouble() const;
</span><span class="cx">     bool asBoolean() const;
</span><span class="cx">     double asNumber() const;
</span><ins>+#if USE(BIGINT32)
+    int32_t bigInt32AsInt32() const; // must only be called on a BigInt32
+#endif
</ins><span class="cx">     
</span><span class="cx">     int32_t asInt32ForArithmetic() const; // Boolean becomes an int, but otherwise like asInt32().
</span><span class="cx"> 
</span><span class="lines">@@ -239,6 +248,8 @@
</span><span class="cx">     bool isNumber() const;
</span><span class="cx">     bool isString() const;
</span><span class="cx">     bool isBigInt() const;
</span><ins>+    bool isHeapBigInt() const;
+    bool isBigInt32() const;
</ins><span class="cx">     bool isSymbol() const;
</span><span class="cx">     bool isPrimitive() const;
</span><span class="cx">     bool isGetterSetter() const;
</span><span class="lines">@@ -247,7 +258,7 @@
</span><span class="cx">     bool inherits(VM&, const ClassInfo*) const;
</span><span class="cx">     template<typename Target> bool inherits(VM&) const;
</span><span class="cx">     const ClassInfo* classInfoOrNull(VM&) const;
</span><del>-        
</del><ins>+
</ins><span class="cx">     // Extracting the value.
</span><span class="cx">     bool getString(JSGlobalObject*, WTF::String&) const;
</span><span class="cx">     WTF::String getString(JSGlobalObject*) const; // null string if not a string
</span><span class="lines">@@ -266,10 +277,11 @@
</span><span class="cx">     // toNumber conversion is expected to be side effect free if an exception has
</span><span class="cx">     // been set in the CallFrame already.
</span><span class="cx">     double toNumber(JSGlobalObject*) const;
</span><del>-    
-    Variant<JSBigInt*, double> toNumeric(JSGlobalObject*) const;
-    Variant<JSBigInt*, int32_t> toBigIntOrInt32(JSGlobalObject*) const;
</del><span class="cx"> 
</span><ins>+    JSValue toNumeric(JSGlobalObject*) const;
+    JSValue toBigIntOrInt32(JSGlobalObject*) const;
+    JSBigInt* asHeapBigInt() const;
+
</ins><span class="cx">     // toNumber conversion if it can be done without side effects.
</span><span class="cx">     Optional<double> toNumberFromPrimitive() const;
</span><span class="cx"> 
</span><span class="lines">@@ -317,8 +329,7 @@
</span><span class="cx">     static bool equalSlowCase(JSGlobalObject*, JSValue v1, JSValue v2);
</span><span class="cx">     static bool equalSlowCaseInline(JSGlobalObject*, JSValue v1, JSValue v2);
</span><span class="cx">     static bool strictEqual(JSGlobalObject*, JSValue v1, JSValue v2);
</span><del>-    static bool strictEqualSlowCase(JSGlobalObject*, JSValue v1, JSValue v2);
-    static bool strictEqualSlowCaseInline(JSGlobalObject*, JSValue v1, JSValue v2);
</del><ins>+    static bool strictEqualForCells(JSGlobalObject*, JSCell* v1, JSCell* v2);
</ins><span class="cx">     static TriState pureStrictEqual(JSValue v1, JSValue v2);
</span><span class="cx"> 
</span><span class="cx">     bool isCell() const;
</span><span class="lines">@@ -416,11 +427,20 @@
</span><span class="cx">      * These values have the following properties:
</span><span class="cx">      * - Bit 1 (OtherTag) is set for all four values, allowing real pointers to be
</span><span class="cx">      *   quickly distinguished from all immediate values, including these invalid pointers.
</span><del>-     * - With bit 3 is masked out (UndefinedTag) Undefined and Null share the
</del><ins>+     * - With bit 3 masked out (UndefinedTag), Undefined and Null share the
</ins><span class="cx">      *   same value, allowing null & undefined to be quickly detected.
</span><span class="cx">      *
</span><span class="cx">      * No valid JSValue will have the bit pattern 0x0, this is used to represent array
</span><span class="cx">      * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0).
</span><ins>+     *
+     * When USE(BIGINT32), we have a special representation for BigInts that are small (32-bit at most):
+     *      0000:XXXX:XXXX:0012
+     * This representation works because of the following things:
+     * - It cannot be confused with a Double or Integer thanks to the top bits
+     * - It cannot be confused with a pointer to a Cell, thanks to bit 1 which is set to true
+     * - It cannot be confused with a pointer to wasm thanks to bit 0 which is set to false
+     * - It cannot be confused with true/false because bit 2 is set to false
+     * - It cannot be confused for null/undefined because bit 4 is set to true
</ins><span class="cx">      */
</span><span class="cx"> 
</span><span class="cx">     // This value is 2^49, used to encode doubles such that the encoded value will begin
</span><span class="lines">@@ -430,11 +450,19 @@
</span><span class="cx">     // If all bits in the mask are set, this indicates an integer number,
</span><span class="cx">     // if any but not all are set this value is a double precision number.
</span><span class="cx">     static constexpr int64_t NumberTag = 0xfffe000000000000ll;
</span><ins>+    // The following constant is used for a trick in the implementation of strictEq, to detect if either of the arguments is a double
+    static constexpr int64_t LowestOfHighBits = 1ULL << 49;
+    static_assert(LowestOfHighBits & NumberTag);
+    static_assert(!((LowestOfHighBits>>1) & NumberTag));
</ins><span class="cx"> 
</span><span class="cx">     // All non-numeric (bool, null, undefined) immediates have bit 2 set.
</span><span class="cx">     static constexpr int32_t OtherTag       = 0x2;
</span><span class="cx">     static constexpr int32_t BoolTag        = 0x4;
</span><span class="cx">     static constexpr int32_t UndefinedTag   = 0x8;
</span><ins>+#if USE(BIGINT32)
+    static constexpr int32_t BigInt32Tag    = 0x12;
+    static constexpr int64_t BigInt32Mask   = NumberTag | BigInt32Tag;
+#endif
</ins><span class="cx">     // Combined integer value for non-numeric immediates.
</span><span class="cx">     static constexpr int32_t ValueFalse     = OtherTag | BoolTag | false;
</span><span class="cx">     static constexpr int32_t ValueTrue      = OtherTag | BoolTag | true;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCJSValueInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h  2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h     2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2019 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -38,7 +38,6 @@
</span><span class="cx"> #include "JSProxy.h"
</span><span class="cx"> #include "JSStringInlines.h"
</span><span class="cx"> #include "MathCommon.h"
</span><del>-#include <wtf/Variant.h>
</del><span class="cx"> #include <wtf/text/StringImpl.h>
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -47,7 +46,9 @@
</span><span class="cx"> {
</span><span class="cx">     if (isInt32())
</span><span class="cx">         return asInt32();
</span><del>-    return JSC::toInt32(toNumber(globalObject));
</del><ins>+
+    double d = toNumber(globalObject);
+    return JSC::toInt32(d);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline uint32_t JSValue::toUInt32(JSGlobalObject* globalObject) const
</span><span class="lines">@@ -329,6 +330,12 @@
</span><span class="cx">     return reinterpret_cast<JSCell*>(u.asBits.payload);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE JSBigInt* JSValue::asHeapBigInt() const
+{
+    ASSERT(isHeapBigInt());
+    return reinterpret_cast<JSBigInt*>(u.asBits.payload);
+}
+
</ins><span class="cx"> ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!isImpureNaN(d));
</span><span class="lines">@@ -522,8 +529,23 @@
</span><span class="cx">     return u.ptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE JSBigInt* JSValue::asHeapBigInt() const
+{
+    ASSERT(isHeapBigInt());
+    return static_cast<JSBigInt*>(u.ptr);
+}
+
</ins><span class="cx"> #endif // USE(JSVALUE64)
</span><span class="cx"> 
</span><ins>+#if USE(BIGINT32)
+inline JSValue::JSValue(JSBigInt32Tag, int32_t value)
+{
+    uint64_t shiftedValue = static_cast<uint64_t>(static_cast<uint32_t>(value)) << 16;
+    ASSERT(!(shiftedValue & NumberTag));
+    u.asInt64 = shiftedValue | BigInt32Tag;
+}
+#endif // USE(BIGINT32)
+
</ins><span class="cx"> inline int64_t tryConvertToInt52(double number)
</span><span class="cx"> {
</span><span class="cx">     if (number != number)
</span><span class="lines">@@ -610,9 +632,31 @@
</span><span class="cx"> 
</span><span class="cx"> inline bool JSValue::isBigInt() const
</span><span class="cx"> {
</span><del>-    return isCell() && asCell()->isBigInt();
</del><ins>+    return isBigInt32() || isHeapBigInt();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool JSValue::isHeapBigInt() const
+{
+    return isCell() && asCell()->isHeapBigInt();
+}
+
+inline bool JSValue::isBigInt32() const
+{
+#if USE(BIGINT32)
+    return (u.asInt64 & BigInt32Mask) == BigInt32Tag;
+#else
+    return false;
+#endif
+}
+
+#if USE(BIGINT32)
+inline int32_t JSValue::bigInt32AsInt32() const
+{
+    ASSERT(isBigInt32());
+    return static_cast<int32_t>(u.asInt64 >> 16);
+}
+#endif // USE(BIGINT32)
+
</ins><span class="cx"> inline bool JSValue::isSymbol() const
</span><span class="cx"> {
</span><span class="cx">     return isCell() && asCell()->isSymbol();
</span><span class="lines">@@ -620,7 +664,7 @@
</span><span class="cx"> 
</span><span class="cx"> inline bool JSValue::isPrimitive() const
</span><span class="cx"> {
</span><del>-    return !isCell() || asCell()->isString() || asCell()->isSymbol() || asCell()->isBigInt();
</del><ins>+    return !isCell() || asCell()->isString() || asCell()->isSymbol() || asCell()->isHeapBigInt();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool JSValue::isGetterSetter() const
</span><span class="lines">@@ -738,6 +782,9 @@
</span><span class="cx"> 
</span><span class="cx"> inline bool JSValue::getPrimitiveNumber(JSGlobalObject* globalObject, double& number, JSValue& value)
</span><span class="cx"> {
</span><ins>+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
</ins><span class="cx">     if (isInt32()) {
</span><span class="cx">         number = asInt32();
</span><span class="cx">         value = *this;
</span><span class="lines">@@ -760,8 +807,15 @@
</span><span class="cx">         value = *this;
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><del>-    ASSERT(isUndefined());
-    number = PNaN;
</del><ins>+    if (isUndefined()) {
+        number = PNaN;
+        value = *this;
+        return true;
+    }
+
+    ASSERT(isBigInt32());
+    throwTypeError(globalObject, scope, "Conversion from 'BigInt' to 'number' is not allowed."_s);
+    number = 0.0;
</ins><span class="cx">     value = *this;
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="lines">@@ -775,44 +829,45 @@
</span><span class="cx">     return toNumberSlowCase(globalObject);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ALWAYS_INLINE Variant<JSBigInt*, double> JSValue::toNumeric(JSGlobalObject* globalObject) const
</del><ins>+ALWAYS_INLINE JSValue JSValue::toNumeric(JSGlobalObject* globalObject) const
</ins><span class="cx"> {
</span><del>-    if (isInt32())
-        return asInt32();
-    if (isDouble())
-        return asDouble();
-    if (isBigInt())
-        return asBigInt(*this);
</del><ins>+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
</ins><span class="cx"> 
</span><del>-    VM& vm = getVM(globalObject);
-    auto scope = DECLARE_THROW_SCOPE(vm);
</del><ins>+    if (isInt32() || isDouble() || isBigInt())
+        return *this;
+
</ins><span class="cx">     JSValue primValue = this->toPrimitive(globalObject, PreferNumber);
</span><del>-    RETURN_IF_EXCEPTION(scope, 0);
-    if (primValue.isBigInt())
-        return asBigInt(primValue);
</del><ins>+    RETURN_IF_EXCEPTION(scope, { });
+
+    if (primValue.isDouble() || primValue.isBigInt())
+        return primValue;
+
</ins><span class="cx">     double value = primValue.toNumber(globalObject);
</span><del>-    RETURN_IF_EXCEPTION(scope, 0);
-    return value;
</del><ins>+    RETURN_IF_EXCEPTION(scope, { });
+
+    return jsNumber(value);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-ALWAYS_INLINE Variant<JSBigInt*, int32_t> JSValue::toBigIntOrInt32(JSGlobalObject* globalObject) const
</del><ins>+ALWAYS_INLINE JSValue JSValue::toBigIntOrInt32(JSGlobalObject* globalObject) const
</ins><span class="cx"> {
</span><del>-    if (isInt32())
-        return asInt32();
</del><ins>+    VM& vm = getVM(globalObject);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    if (isInt32() || isBigInt())
+        return *this;
</ins><span class="cx">     if (isDouble() && canBeInt32(asDouble()))
</span><del>-        return static_cast<int32_t>(asDouble());
-    if (isBigInt())
-        return asBigInt(*this);
</del><ins>+        return jsNumber(static_cast<int32_t>(asDouble()));
</ins><span class="cx"> 
</span><del>-    VM& vm = getVM(globalObject);
-    auto scope = DECLARE_THROW_SCOPE(vm);
</del><span class="cx">     JSValue primValue = this->toPrimitive(globalObject, PreferNumber);
</span><del>-    RETURN_IF_EXCEPTION(scope, 0);
-    if (primValue.isBigInt())
-        return asBigInt(primValue);
</del><ins>+    RETURN_IF_EXCEPTION(scope, { });
+
+    if (primValue.isInt32() || primValue.isBigInt())
+        return primValue;
+
</ins><span class="cx">     int32_t value = primValue.toInt32(globalObject);
</span><del>-    RETURN_IF_EXCEPTION(scope, 0);
-    return value;
</del><ins>+    RETURN_IF_EXCEPTION(scope, { });
+    return jsNumber(value);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline JSObject* JSValue::toObject(JSGlobalObject* globalObject) const
</span><span class="lines">@@ -1039,37 +1094,17 @@
</span><span class="cx">     VM& vm = getVM(globalObject);
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><span class="cx">     do {
</span><del>-        if (v1.isNumber() && v2.isNumber())
-            return v1.asNumber() == v2.asNumber();
-
-        bool s1 = v1.isString();
-        bool s2 = v2.isString();
-        if (s1 && s2)
-            RELEASE_AND_RETURN(scope, asString(v1)->equal(globalObject, asString(v2)));
-
-        if (v1.isBigInt() && s2) {
-            String v2String = asString(v2)->value(globalObject);
-            RETURN_IF_EXCEPTION(scope, false);
-            JSBigInt* n = JSBigInt::stringToBigInt(globalObject, v2String);
-            RETURN_IF_EXCEPTION(scope, false);
-            if (!n)
-                return false;
-            
-            v2 = JSValue(n);
-            continue;
</del><ins>+        if (v1.isNumber()) {
+            if (v2.isNumber())
+                return v1.asNumber() == v2.asNumber();
+            // Guaranteeing that if we have a number it is v2 makes some of the cases below simpler.
+            std::swap(v1, v2);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (s1 && v2.isBigInt()) {
-            String v1String = asString(v1)->value(globalObject);
-            RETURN_IF_EXCEPTION(scope, false);
-            JSBigInt* n = JSBigInt::stringToBigInt(globalObject, v1String);
-            RETURN_IF_EXCEPTION(scope, false);
-            if (!n)
-                return false;
-            
-            v1 = JSValue(n);
-            continue;
-        }
</del><ins>+        // This deals with Booleans, BigInt32, Objects, and is a shortcut for a few more types.
+        // It has to come here and not before, because it is NOT true that NaN == NaN
+        if (v1 == v2)
+            return true;
</ins><span class="cx"> 
</span><span class="cx">         if (v1.isUndefinedOrNull()) {
</span><span class="cx">             if (v2.isUndefinedOrNull())
</span><span class="lines">@@ -1087,7 +1122,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (v1.isObject()) {
</span><span class="cx">             if (v2.isObject())
</span><del>-                return v1 == v2;
</del><ins>+                return false; // v1 == v2 is already dealt with previously
</ins><span class="cx">             JSValue p1 = v1.toPrimitive(globalObject);
</span><span class="cx">             RETURN_IF_EXCEPTION(scope, false);
</span><span class="cx">             v1 = p1;
</span><span class="lines">@@ -1109,56 +1144,86 @@
</span><span class="cx">         bool sym2 = v2.isSymbol();
</span><span class="cx">         if (sym1 || sym2) {
</span><span class="cx">             if (sym1 && sym2)
</span><del>-                return asSymbol(v1) == asSymbol(v2);
</del><ins>+                return false; // v1 == v2 is already dealt with previously
</ins><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        bool s1 = v1.isString();
+        bool s2 = v2.isString();
+        if (s1) {
+            if (s2)
+                RELEASE_AND_RETURN(scope, asString(v1)->equal(globalObject, asString(v2)));
+            std::swap(v1, v2);
+            // We are guaranteed to enter the next case, so losing the invariant of only v2 being a number is fine
+        }
</ins><span class="cx">         if (s1 || s2) {
</span><del>-            double d1 = v1.toNumber(globalObject);
-            RETURN_IF_EXCEPTION(scope, false);
-            double d2 = v2.toNumber(globalObject);
-            RETURN_IF_EXCEPTION(scope, false);
-            return d1 == d2;
</del><ins>+            // We are guaranteed that the string is v2 (thanks to the swap above)
+            if (v1.isBigInt()) {
+                String v2String = asString(v2)->value(globalObject);
+                RETURN_IF_EXCEPTION(scope, false);
+                v2 = JSBigInt::stringToBigInt(globalObject, v2String);
+                RETURN_IF_EXCEPTION(scope, false);
+                if (!v2)
+                    return false;
+                if (v1 == v2)
+                    return true; // For BigInt32
+                // We fallthrough to the generic code for comparing BigInts (which is only missing the BigInt32/BigInt32 case, hence the check above)
+            } else {
+                ASSERT(v1.isNumber() || v1.isBoolean());
+                double d1 = v1.toNumber(globalObject);
+                RETURN_IF_EXCEPTION(scope, false);
+                double d2 = v2.toNumber(globalObject);
+                RETURN_IF_EXCEPTION(scope, false);
+                return d1 == d2;
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (v1.isBoolean()) {
</span><span class="cx">             if (v2.isNumber())
</span><span class="cx">                 return static_cast<double>(v1.asBoolean()) == v2.asNumber();
</span><del>-            else if (v2.isBigInt()) {
-                v1 = JSValue(v1.toNumber(globalObject));
-                continue;
-            }
</del><ins>+            v1 = JSValue(v1.toNumber(globalObject));
+            RETURN_IF_EXCEPTION(scope, false);
+            // We fallthrough to the BigInt/Number comparison below
+            // We just need one more swap to repair the rule that only v2 is allowed to be a number in these comparisons
+            std::swap(v1, v2);
</ins><span class="cx">         } else if (v2.isBoolean()) {
</span><del>-            if (v1.isNumber())
-                return v1.asNumber() == static_cast<double>(v2.asBoolean());
-            else if (v1.isBigInt()) {
-                v2 = JSValue(v2.toNumber(globalObject));
-                continue;
-            }
</del><ins>+            v2 = JSValue(v2.toNumber(globalObject));
+            RETURN_IF_EXCEPTION(scope, false);
+            // We fallthrough to the BigInt/Number comparison below
</ins><span class="cx">         }
</span><del>-        
-        if (v1.isBigInt() && v2.isBigInt())
-            return JSBigInt::equals(asBigInt(v1), asBigInt(v2));
-        
-        if (v1.isBigInt() && v2.isNumber())
-            return asBigInt(v1)->equalsToNumber(v2);
</del><span class="cx"> 
</span><del>-        if (v2.isBigInt() && v1.isNumber())
-            return asBigInt(v2)->equalsToNumber(v1);
</del><ins>+#if USE(BIGINT32)
+        if (v1.isBigInt32()) {
+            if (v2.isInt32())
+                return v1.bigInt32AsInt32() == v2.asInt32();
+            if (v2.isDouble())
+                return static_cast<double>(v1.bigInt32AsInt32()) == v2.asDouble();
+            std::swap(v1, v2);
+        }
+#endif // USE(BIGINT32)
</ins><span class="cx"> 
</span><del>-        return v1 == v2;
</del><ins>+        if (v1.isHeapBigInt()) {
+            if (v2.isHeapBigInt())
+                return JSBigInt::equals(v1.asHeapBigInt(), v2.asHeapBigInt());
+#if USE(BIGINT32)
+            if (v2.isBigInt32())
+                return v1.asHeapBigInt()->equalsToInt32(v2.bigInt32AsInt32());
+#endif // USE(BIGINT32)
+            if (v2.isNumber())
+                return v1.asHeapBigInt()->equalsToNumber(v2);
+        }
+
+        return false;
</ins><span class="cx">     } while (true);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // ECMA 11.9.3
</span><del>-ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(JSGlobalObject* globalObject, JSValue v1, JSValue v2)
</del><ins>+ALWAYS_INLINE bool JSValue::strictEqualForCells(JSGlobalObject* globalObject, JSCell* v1, JSCell* v2)
</ins><span class="cx"> {
</span><del>-    ASSERT(v1.isCell() && v2.isCell());
-
-    if (v1.asCell()->isString() && v2.asCell()->isString())
</del><ins>+    if (v1->isString() && v2->isString())
</ins><span class="cx">         return asString(v1)->equal(globalObject, asString(v2));
</span><del>-    if (v1.isBigInt() && v2.isBigInt())
-        return JSBigInt::equals(asBigInt(v1), asBigInt(v2));
</del><ins>+    if (v1->isHeapBigInt() && v2->isHeapBigInt())
+        return JSBigInt::equals(static_cast<JSBigInt*>(v1), static_cast<JSBigInt*>(v2));
</ins><span class="cx">     return v1 == v2;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1170,10 +1235,17 @@
</span><span class="cx">     if (v1.isNumber() && v2.isNumber())
</span><span class="cx">         return v1.asNumber() == v2.asNumber();
</span><span class="cx"> 
</span><del>-    if (!v1.isCell() || !v2.isCell())
-        return v1 == v2;
</del><ins>+#if USE(BIGINT32)
+    if (v1.isHeapBigInt() && v2.isBigInt32())
+        return v1.asHeapBigInt()->equalsToInt32(v2.bigInt32AsInt32());
+    if (v1.isBigInt32() && v2.isHeapBigInt())
+        return v2.asHeapBigInt()->equalsToInt32(v1.bigInt32AsInt32());
+#endif
</ins><span class="cx"> 
</span><del>-    return strictEqualSlowCaseInline(globalObject, v1, v2);
</del><ins>+    if (v1.isCell() && v2.isCell())
+        return strictEqualForCells(globalObject, v1.asCell(), v2.asCell());
+
+    return v1 == v2;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline int32_t JSValue::asInt32ForArithmetic() const
</span><span class="lines">@@ -1191,15 +1263,23 @@
</span><span class="cx">     if (v1.isNumber() && v2.isNumber())
</span><span class="cx">         return triState(v1.asNumber() == v2.asNumber());
</span><span class="cx"> 
</span><del>-    if (!v1.isCell() || !v2.isCell())
-        return triState(v1 == v2);
-    
-    if (v1.asCell()->isString() && v2.asCell()->isString()) {
-        const StringImpl* v1String = asString(v1)->tryGetValueImpl();
-        const StringImpl* v2String = asString(v2)->tryGetValueImpl();
-        if (!v1String || !v2String)
-            return MixedTriState;
-        return triState(WTF::equal(*v1String, *v2String));
</del><ins>+#if USE(BIGINT32)
+    if (v1.isHeapBigInt() && v2.isBigInt32())
+        return triState(v1.asHeapBigInt()->equalsToInt32(v2.bigInt32AsInt32()));
+    if (v1.isBigInt32() && v2.isHeapBigInt())
+        return triState(v2.asHeapBigInt()->equalsToInt32(v1.bigInt32AsInt32()));
+#endif
+
+    if (v1.isCell() && v2.isCell()) {
+        if (v1.asCell()->isString() && v2.asCell()->isString()) {
+            const StringImpl* v1String = asString(v1)->tryGetValueImpl();
+            const StringImpl* v2String = asString(v2)->tryGetValueImpl();
+            if (!v1String || !v2String)
+                return MixedTriState;
+            return triState(WTF::equal(*v1String, *v2String));
+        }
+        if (v1.asCell()->isHeapBigInt() && v2.asCell()->isHeapBigInt())
+            return triState(JSBigInt::equals(v1.asHeapBigInt(), v2.asHeapBigInt()));
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     return triState(v1 == v2);
</span><span class="lines">@@ -1213,6 +1293,10 @@
</span><span class="cx">         return isNotZeroAndOrdered(asDouble()) ? TrueTriState : FalseTriState; // false for NaN
</span><span class="cx">     if (isCell())
</span><span class="cx">         return asCell()->pureToBoolean();
</span><ins>+#if USE(BIGINT32)
+    if (isBigInt32())
+        return bigInt32AsInt32() ? TrueTriState : FalseTriState;
+#endif
</ins><span class="cx">     return isTrue() ? TrueTriState : FalseTriState;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCellcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCell.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCell.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSCell.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -113,7 +113,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool JSCell::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName identifier, JSValue value, PutPropertySlot& slot)
</span><span class="cx"> {
</span><del>-    if (cell->isString() || cell->isSymbol() || cell->isBigInt())
</del><ins>+    if (cell->isString() || cell->isSymbol() || cell->isHeapBigInt())
</ins><span class="cx">         return JSValue(cell).putToPrimitive(globalObject, identifier, value, slot);
</span><span class="cx"> 
</span><span class="cx">     JSObject* thisObject = cell->toObject(globalObject);
</span><span class="lines">@@ -123,7 +123,7 @@
</span><span class="cx"> bool JSCell::putByIndex(JSCell* cell, JSGlobalObject* globalObject, unsigned identifier, JSValue value, bool shouldThrow)
</span><span class="cx"> {
</span><span class="cx">     VM& vm = globalObject->vm();
</span><del>-    if (cell->isString() || cell->isSymbol() || cell->isBigInt()) {
</del><ins>+    if (cell->isString() || cell->isSymbol() || cell->isHeapBigInt()) {
</ins><span class="cx">         PutPropertySlot slot(cell, shouldThrow);
</span><span class="cx">         return JSValue(cell).putToPrimitive(globalObject, Identifier::from(vm, identifier), value, slot);
</span><span class="cx">     }
</span><span class="lines">@@ -163,7 +163,7 @@
</span><span class="cx">         return static_cast<const JSString*>(this)->toPrimitive(globalObject, preferredType);
</span><span class="cx">     if (isSymbol())
</span><span class="cx">         return static_cast<const Symbol*>(this)->toPrimitive(globalObject, preferredType);
</span><del>-    if (isBigInt())
</del><ins>+    if (isHeapBigInt())
</ins><span class="cx">         return static_cast<const JSBigInt*>(this)->toPrimitive(globalObject, preferredType);
</span><span class="cx">     return static_cast<const JSObject*>(this)->toPrimitive(globalObject, preferredType);
</span><span class="cx"> }
</span><span class="lines">@@ -174,7 +174,7 @@
</span><span class="cx">         return static_cast<const JSString*>(this)->getPrimitiveNumber(globalObject, number, value);
</span><span class="cx">     if (isSymbol())
</span><span class="cx">         return static_cast<const Symbol*>(this)->getPrimitiveNumber(globalObject, number, value);
</span><del>-    if (isBigInt())
</del><ins>+    if (isHeapBigInt())
</ins><span class="cx">         return static_cast<const JSBigInt*>(this)->getPrimitiveNumber(globalObject, number, value);
</span><span class="cx">     return static_cast<const JSObject*>(this)->getPrimitiveNumber(globalObject, number, value);
</span><span class="cx"> }
</span><span class="lines">@@ -185,7 +185,7 @@
</span><span class="cx">         return static_cast<const JSString*>(this)->toNumber(globalObject);
</span><span class="cx">     if (isSymbol())
</span><span class="cx">         return static_cast<const Symbol*>(this)->toNumber(globalObject);
</span><del>-    if (isBigInt())
</del><ins>+    if (isHeapBigInt())
</ins><span class="cx">         return static_cast<const JSBigInt*>(this)->toNumber(globalObject);
</span><span class="cx">     return static_cast<const JSObject*>(this)->toNumber(globalObject);
</span><span class="cx"> }
</span><span class="lines">@@ -196,7 +196,7 @@
</span><span class="cx">     ASSERT(!isObject());
</span><span class="cx">     if (isString())
</span><span class="cx">         return static_cast<const JSString*>(this)->toObject(globalObject);
</span><del>-    if (isBigInt())
</del><ins>+    if (isHeapBigInt())
</ins><span class="cx">         return static_cast<const JSBigInt*>(this)->toObject(globalObject);
</span><span class="cx">     ASSERT(isSymbol());
</span><span class="cx">     return static_cast<const Symbol*>(this)->toObject(globalObject);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCellh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCell.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCell.h     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSCell.h        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -101,7 +101,7 @@
</span><span class="cx"> public:
</span><span class="cx">     // Querying the type.
</span><span class="cx">     bool isString() const;
</span><del>-    bool isBigInt() const;
</del><ins>+    bool isHeapBigInt() const;
</ins><span class="cx">     bool isSymbol() const;
</span><span class="cx">     bool isObject() const;
</span><span class="cx">     bool isGetterSetter() const;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCellInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCellInlines.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCellInlines.h      2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSCellInlines.h 2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -204,9 +204,9 @@
</span><span class="cx">     return m_type == StringType;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline bool JSCell::isBigInt() const
</del><ins>+inline bool JSCell::isHeapBigInt() const
</ins><span class="cx"> {
</span><del>-    return m_type == BigIntType;
</del><ins>+    return m_type == HeapBigIntType;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool JSCell::isSymbol() const
</span><span class="lines">@@ -340,7 +340,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (isString())
</span><span class="cx">         return static_cast<const JSString*>(this)->toBoolean();
</span><del>-    if (isBigInt())
</del><ins>+    if (isHeapBigInt())
</ins><span class="cx">         return static_cast<const JSBigInt*>(this)->toBoolean();
</span><span class="cx">     return !structure(getVM(globalObject))->masqueradesAsUndefined(globalObject);
</span><span class="cx"> }
</span><span class="lines">@@ -349,7 +349,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (isString())
</span><span class="cx">         return static_cast<const JSString*>(this)->toBoolean() ? TrueTriState : FalseTriState;
</span><del>-    if (isBigInt())
</del><ins>+    if (isHeapBigInt())
</ins><span class="cx">         return static_cast<const JSBigInt*>(this)->toBoolean() ? TrueTriState : FalseTriState;
</span><span class="cx">     if (isSymbol())
</span><span class="cx">         return TrueTriState;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSGlobalObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1068,6 +1068,7 @@
</span><span class="cx"> {
</span><span class="cx">     VM& vm = getVM(globalObject);
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><ins>+
</ins><span class="cx">     Structure* structure;
</span><span class="cx">     if (initialLength >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)
</span><span class="cx">         structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(globalObject, ArrayWithArrayStorage, newTarget);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSStringh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSString.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSString.h   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSString.h      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1038,6 +1038,10 @@
</span><span class="cx">         return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
</span><span class="cx">     if (isCell())
</span><span class="cx">         return asCell()->toBoolean(globalObject);
</span><ins>+#if USE(BIGINT32)
+    if (isBigInt32())
+        return !!bigInt32AsInt32();
+#endif
</ins><span class="cx">     return isTrue(); // false, null, and undefined all convert to false.
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSTypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSType.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSType.cpp   2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSType.cpp      2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -43,7 +43,7 @@
</span><span class="cx">     CASE(CellType)
</span><span class="cx">     CASE(StringType)
</span><span class="cx">     CASE(SymbolType)
</span><del>-    CASE(BigIntType)
</del><ins>+    CASE(HeapBigIntType)
</ins><span class="cx">     CASE(CustomGetterSetterType)
</span><span class="cx">     CASE(APIValueWrapperType)
</span><span class="cx">     CASE(NativeExecutableType)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSType.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSType.h     2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSType.h        2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -26,8 +26,8 @@
</span><span class="cx">     // The CellType value must come before any JSType that is a JSCell.
</span><span class="cx">     CellType,
</span><span class="cx">     StringType,
</span><del>-    BigIntType,
-    LastMaybeFalsyCellPrimitive = BigIntType,
</del><ins>+    HeapBigIntType,
+    LastMaybeFalsyCellPrimitive = HeapBigIntType,
</ins><span class="cx">     SymbolType,
</span><span class="cx"> 
</span><span class="cx">     GetterSetterType,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSTypeInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSTypeInfo.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSTypeInfo.h 2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/JSTypeInfo.h    2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -134,7 +134,7 @@
</span><span class="cx">     bool isSetOnFlags1(unsigned flag) const { ASSERT(flag <= (1 << 7)); return m_flags & flag; }
</span><span class="cx">     bool isSetOnFlags2(unsigned flag) const { ASSERT(flag >= (1 << 8)); return m_flags2 & (flag >> 8); }
</span><span class="cx"> 
</span><del>-    uint8_t m_type;
</del><ins>+    JSType m_type;
</ins><span class="cx">     uint8_t m_flags;
</span><span class="cx">     uint16_t m_flags2;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeObjectInitializationScopecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ObjectInitializationScope.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ObjectInitializationScope.cpp        2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/ObjectInitializationScope.cpp   2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -26,9 +26,8 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "ObjectInitializationScope.h"
</span><span class="cx"> 
</span><del>-#include "JSCInlines.h"
</del><span class="cx"> #include "JSObject.h"
</span><del>-#include "Operations.h"
</del><ins>+#include "Scribble.h"
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Operations.cpp (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Operations.cpp       2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/Operations.cpp  2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
</span><del>- * Copyright (C) 2008, 2016 Apple Inc. All Rights Reserved.
</del><ins>+ * Copyright (C) 2008-2020 Apple Inc. All Rights Reserved.
</ins><span class="cx">  *
</span><span class="cx">  *  This library is free software; you can redistribute it and/or
</span><span class="cx">  *  modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -36,11 +36,6 @@
</span><span class="cx">     return equalSlowCaseInline(globalObject, v1, v2);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool JSValue::strictEqualSlowCase(JSGlobalObject* globalObject, JSValue v1, JSValue v2)
-{
-    return strictEqualSlowCaseInline(globalObject, v1, v2);
-}
-
</del><span class="cx"> NEVER_INLINE JSValue jsAddSlowCase(JSGlobalObject* globalObject, JSValue v1, JSValue v2)
</span><span class="cx"> {
</span><span class="cx">     // exception for the Date exception in defaultValue()
</span><span class="lines">@@ -73,21 +68,23 @@
</span><span class="cx">         RELEASE_AND_RETURN(scope, jsString(globalObject, p1String, asString(p2)));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    auto leftNumeric = p1.toNumeric(globalObject);
-    RETURN_IF_EXCEPTION(scope, { });
-    auto rightNumeric = p2.toNumeric(globalObject);
-    RETURN_IF_EXCEPTION(scope, { });
-
-    if (WTF::holds_alternative<JSBigInt*>(leftNumeric) || WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-        if (WTF::holds_alternative<JSBigInt*>(leftNumeric) && WTF::holds_alternative<JSBigInt*>(rightNumeric)) {
-            scope.release();
-            return JSBigInt::add(globalObject, WTF::get<JSBigInt*>(leftNumeric), WTF::get<JSBigInt*>(rightNumeric));
-        }
-
-        return throwTypeError(globalObject, scope, "Invalid mix of BigInt and other type in addition."_s);
-    }
-
-    return jsNumber(WTF::get<double>(leftNumeric) + WTF::get<double>(rightNumeric));
</del><ins>+    auto doubleOp = [] (double left, double right) -> double {
+        return left + right;
+    };
+    auto bigInt32Op = [] (int32_t left, int32_t right) -> JSValue {
+#if USE(BIGINT32)
+        CheckedInt32 result = left;
+        result += right;
+        if (UNLIKELY(result.hasOverflowed()))
+            return JSValue();
+        return JSValue(JSValue::JSBigInt32, result.unsafeGet());
+#else
+        UNUSED_PARAM(left);
+        UNUSED_PARAM(right);
+        RELEASE_ASSERT_NOT_REACHED();
+#endif
+    };
+    RELEASE_AND_RETURN(scope, arithmeticBinaryOp(globalObject, p1, p2, JSBigInt::add, doubleOp, bigInt32Op, "Invalid mix of BigInt and other type in addition."_s));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSValue jsTypeStringForValue(VM& vm, JSGlobalObject* globalObject, JSValue v)
</span><span class="lines">@@ -128,7 +125,7 @@
</span><span class="cx">         return v.isNull();
</span><span class="cx"> 
</span><span class="cx">     JSType type = v.asCell()->type();
</span><del>-    if (type == StringType || type == SymbolType || type == BigIntType)
</del><ins>+    if (type == StringType || type == SymbolType || type == HeapBigIntType)
</ins><span class="cx">         return false;
</span><span class="cx">     if (type >= ObjectType) {
</span><span class="cx">         if (asObject(v)->structure(vm)->masqueradesAsUndefined(globalObject))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOperationsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Operations.h (260330 => 260331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Operations.h 2020-04-19 02:08:52 UTC (rev 260330)
+++ trunk/Source/JavaScriptCore/runtime/Operations.h    2020-04-19 02:20:59 UTC (rev 260331)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
</span><del>- *  Copyright (C) 2002-2019 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2002-2020 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  *  This library is free software; you can redistribute it and/or
</span><span class="cx">  *  modify it under the terms of the GNU Library General Public
</span><span class="lines">@@ -25,7 +25,6 @@
</span><span class="cx"> #include "ExceptionHelpers.h"
</span><span class="cx"> #include "JSBigInt.h"
</span><span class="cx"> #include "JSCJSValueInlines.h"
</span><del>-#include <wtf/Variant.h>
</del><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -239,6 +238,35 @@
</span><span class="cx">     return ropeBuilder.release();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE JSBigInt::ComparisonResult compareBigIntToOtherPrimitive(JSGlobalObject* globalObject, JSBigInt* v1, JSValue primValue)
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    ASSERT(primValue.isPrimitive());
+    ASSERT(!primValue.isBigInt());
+
+    if (primValue.isString()) {
+        JSValue bigIntValue = JSBigInt::stringToBigInt(globalObject, asString(primValue)->value(globalObject));
+        RETURN_IF_EXCEPTION(scope, JSBigInt::ComparisonResult::Undefined);
+        if (!bigIntValue)
+            return JSBigInt::ComparisonResult::Undefined;
+
+        if (bigIntValue.isHeapBigInt())
+            return JSBigInt::compare(v1, bigIntValue.asHeapBigInt());
+
+        ASSERT(bigIntValue.isBigInt32());
+#if USE(BIGINT32)
+        // FIXME: use something less hacky, e.g. some kind of JSBigInt::compareToInt32
+        return JSBigInt::compareToDouble(v1, static_cast<double>(bigIntValue.bigInt32AsInt32()));
+#endif
+    }
+
+    double numberValue = primValue.toNumber(globalObject);
+    RETURN_IF_EXCEPTION(scope, JSBigInt::ComparisonResult::Undefined);
+    return JSBigInt::compareToDouble(v1, numberValue);
+}
+
</ins><span class="cx"> ALWAYS_INLINE bool bigIntCompareResult(JSBigInt::ComparisonResult comparisonResult, JSBigInt::ComparisonMode comparisonMode)
</span><span class="cx"> {
</span><span class="cx">     if (comparisonMode == JSBigInt::ComparisonMode::LessThan)
</span><span class="lines">@@ -255,50 +283,47 @@
</span><span class="cx"> 
</span><span class="cx">     VM& vm = globalObject->vm();
</span><span class="cx">     auto scope = DECLARE_THROW_SCOPE(vm);
</span><del>-    
-    if (v1.isBigInt() && v2.isBigInt())
-        return bigIntCompareResult(JSBigInt::compare(asBigInt(v1), asBigInt(v2)), comparisonMode);
-    
-    if (v1.isBigInt()) {
-        JSValue primValue = v2;
-        if (primValue.isString()) {
-            JSBigInt* bigIntValue = JSBigInt::stringToBigInt(globalObject, asString(primValue)->value(globalObject));
-            RETURN_IF_EXCEPTION(scope, false);
-            if (!bigIntValue)
-                return false;
</del><span class="cx"> 
</span><del>-            return bigIntCompareResult(JSBigInt::compare(asBigInt(v1), bigIntValue), comparisonMode);
-        }
</del><ins>+#if USE(BIGINT32)
+    if (v1.isBigInt32() && v2.isBigInt32()) {
+        if (comparisonMode == JSBigInt::ComparisonMode::LessThan)
+            return v1.bigInt32AsInt32() < v2.bigInt32AsInt32();
+        ASSERT(comparisonMode == JSBigInt::ComparisonMode::LessThanOrEqual);
+        return v1.bigInt32AsInt32() <= v2.bigInt32AsInt32();
+    }
+#endif
</ins><span class="cx"> 
</span><del>-        if (primValue.isBigInt())
-            return bigIntCompareResult(JSBigInt::compare(asBigInt(v1), asBigInt(primValue)), comparisonMode);
</del><ins>+    JSBigInt* v1HeapBigInt = nullptr;
+    JSBigInt* v2HeapBigInt = nullptr;
+    // FIXME: have some fast-ish path for a comparison between a small and a large big-int
+    if (v1.isHeapBigInt())
+        v1HeapBigInt = v1.asHeapBigInt();
+#if USE(BIGINT32)
+    else if (v1.isBigInt32())
+        v1HeapBigInt = JSBigInt::createFrom(vm, v1.bigInt32AsInt32());
+#endif
</ins><span class="cx"> 
</span><del>-        double numberValue = primValue.toNumber(globalObject);
</del><ins>+    if (v2.isHeapBigInt())
+        v2HeapBigInt = v2.asHeapBigInt();
+#if USE(BIGINT32)
+    else if (v2.isBigInt32())
+        v2HeapBigInt = JSBigInt::createFrom(vm, v2.bigInt32AsInt32());
+#endif
+
+    if (v1HeapBigInt && v2HeapBigInt)
+        return bigIntCompareResult(JSBigInt::compare(v1HeapBigInt, v2HeapBigInt), comparisonMode);
+
+    if (v1HeapBigInt) {
+        auto comparisonResult = compareBigIntToOtherPrimitive(globalObject, v1HeapBigInt, v2);
</ins><span class="cx">         RETURN_IF_EXCEPTION(scope, false);
</span><del>-        return bigIntCompareResult(JSBigInt::compareToDouble(asBigInt(v1), numberValue), comparisonMode);
</del><ins>+        return bigIntCompareResult(comparisonResult, comparisonMode);
</ins><span class="cx">     }
</span><del>-    
-    JSValue primValue = v1;
-    if (primValue.isString()) {
-        JSBigInt* bigIntValue = JSBigInt::stringToBigInt(globalObject, asString(primValue)->value(globalObject));
-        RETURN_IF_EXCEPTION(scope, false);
-        if (!bigIntValue)
-            return false;
</del><span class="cx"> 
</span><del>-        return bigIntCompareResult(JSBigInt::compare(bigIntValue, asBigInt(v2)), comparisonMode);
-    }
-&nbs