Source/JavaScriptCore/ChangeLog

 12020-04-22 Yusuke Suzuki <ysuzuki@apple.com>
 2
 3 [JSC] branchIfBigInt32 can use BigInt32Mask and remove branchIfNumber filter
 4 https://bugs.webkit.org/show_bug.cgi?id=210870
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 By using BigInt32Mask, we can detect BigInt32 without filtering Numbers. In this patch,
 9
 10 1. Remove branchIfBigInt32KnownNotNumber and branchIfNotBigInt32KnownNotNumber. And always use branchBigInt32 and branchNotBigInt32 instead.
 11 2. Remove branchIfNumber type filtering in DFG.
 12 3. Use BigInt32Mask based scheme in FTL.
 13 4. Add and64(TrustedImm64, RegisterID) implementations in MacroAssembler.
 14
 15 * assembler/MacroAssemblerARM64.h:
 16 (JSC::MacroAssemblerARM64::and64):
 17 * assembler/MacroAssemblerX86_64.h:
 18 (JSC::MacroAssemblerX86_64::and64):
 19 * bytecode/ArithProfile.cpp:
 20 (JSC::ArithProfile<BitfieldType>::emitObserveResult):
 21 * dfg/DFGSpeculativeJIT64.cpp:
 22 (JSC::DFG::SpeculativeJIT::fillSpeculateBigInt32):
 23 * ftl/FTLLowerDFGToB3.cpp:
 24 (JSC::FTL::DFG::LowerDFGToB3::compileToNumeric):
 25 (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
 26 (JSC::FTL::DFG::LowerDFGToB3::compileIsBigInt):
 27 (JSC::FTL::DFG::LowerDFGToB3::boolify):
 28 (JSC::FTL::DFG::LowerDFGToB3::buildTypeOf):
 29 (JSC::FTL::DFG::LowerDFGToB3::lowBigInt32):
 30 (JSC::FTL::DFG::LowerDFGToB3::isBigInt32):
 31 (JSC::FTL::DFG::LowerDFGToB3::isNotBigInt32):
 32 (JSC::FTL::DFG::LowerDFGToB3::isNotAnyBigInt):
 33 (JSC::FTL::DFG::LowerDFGToB3::speculateBigInt32):
 34 (JSC::FTL::DFG::LowerDFGToB3::speculateAnyBigInt):
 35 (JSC::FTL::DFG::LowerDFGToB3::isBigInt32KnownNotCell): Deleted.
 36 (JSC::FTL::DFG::LowerDFGToB3::isBigInt32KnownNotNumber): Deleted.
 37 (JSC::FTL::DFG::LowerDFGToB3::isNotBigInt32KnownNotNumber): Deleted.
 38 (JSC::FTL::DFG::LowerDFGToB3::isNotAnyBigIntKnownNotNumber): Deleted.
 39 * jit/AssemblyHelpers.cpp:
 40 (JSC::AssemblyHelpers::emitConvertValueToBoolean):
 41 (JSC::AssemblyHelpers::branchIfValue):
 42 * jit/AssemblyHelpers.h:
 43 (JSC::AssemblyHelpers::branchIfBigInt32):
 44 (JSC::AssemblyHelpers::branchIfNotBigInt32):
 45 (JSC::AssemblyHelpers::emitTypeOf):
 46 (JSC::AssemblyHelpers::branchIfBigInt32KnownNotNumber): Deleted.
 47 (JSC::AssemblyHelpers::branchIfNotBigInt32KnownNotNumber): Deleted.
 48
1492020-04-22 Yusuke Suzuki <ysuzuki@apple.com>
250
351 [JSC] JSBigInt inc operation does not produce right HeapBigInt zero

Source/JavaScriptCore/assembler/MacroAssemblerARM64.h

@@class MacroAssemblerARM64 : public AbstractMacroAssembler<Assembler> {
416416 }
417417
418418 void and64(TrustedImmPtr imm, RegisterID dest)
 419 {
 420 intptr_t value = imm.asIntPtr();
 421 if constexpr (sizeof(void*) == sizeof(uint64_t))
 422 and64(TrustedImm64(value), dest);
 423 else
 424 and64(TrustedImm32(static_cast<int32_t>(value)), dest);
 425 }
 426
 427 void and64(TrustedImm64 imm, RegisterID dest)
419428 {
420429 LogicalImmediate logicalImm = LogicalImmediate::create64(reinterpret_cast<uint64_t>(imm.m_value));
421430

Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h

@@class MacroAssemblerX86_64 : public MacroAssemblerX86Common {
441441
442442 void and64(TrustedImmPtr imm, RegisterID srcDest)
443443 {
444  intptr_t intValue = imm.asIntptr();
 444 static_assert(sizeof(void*) == sizeof(int64_t));
 445 and64(TrustedImm64(bitwise_cast<int64_t>(imm.m_value)), srcDest);
 446 }
 447
 448 void and64(TrustedImm64 imm, RegisterID srcDest)
 449 {
 450 int64_t intValue = imm.m_value;
445451 if (intValue <= std::numeric_limits<int32_t>::max()
446452 && intValue >= std::numeric_limits<int32_t>::min()) {
447453 and64(TrustedImm32(static_cast<int32_t>(intValue)), srcDest);

Source/JavaScriptCore/bytecode/ArithProfile.cpp

@@void ArithProfile<BitfieldType>::emitObserveResult(CCallHelpers& jit, JSValueReg
4949 notDouble.link(&jit);
5050
5151#if USE(BIGINT32)
52  CCallHelpers::Jump notBigInt32 = jit.branchIfNotBigInt32KnownNotNumber(regs, tempGPR);
 52 CCallHelpers::Jump notBigInt32 = jit.branchIfNotBigInt32(regs, tempGPR);
5353 emitSetBigInt32(jit);
5454 done.append(jit.jump());
5555 notBigInt32.link(&jit);

Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

@@GPRReg SpeculativeJIT::fillSpeculateBigInt32(Edge edge)
14691469 if (type & ~SpecBigInt32) {
14701470 CCallHelpers::JumpList failureCases;
14711471 GPRReg tempGPR = allocate();
1472  failureCases.append(m_jit.branchIfNumber(gpr));
1473  failureCases.append(m_jit.branchIfNotBigInt32KnownNotNumber(gpr, tempGPR));
 1472 failureCases.append(m_jit.branchIfNotBigInt32(gpr, tempGPR));
14741473 speculationCheck(BadType, JSValueRegs(gpr), edge, failureCases);
14751474 unlock(tempGPR);
14761475 }

Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

@@class LowerDFGToB3 {
75547554 // notNumber case.
75557555 LBasicBlock lastNext = m_out.appendTo(notNumber, continuation);
75567556#if USE(BIGINT32)
7557  m_out.branch(isBigInt32KnownNotNumber(value, provenType(m_node->child1())), unsure(continuation), unsure(notBigInt32));
 7557 m_out.branch(isBigInt32(value, provenType(m_node->child1())), unsure(continuation), unsure(notBigInt32));
75587558 m_out.appendTo(notBigInt32);
75597559#endif
75607560 m_out.branch(isCell(value, provenType(m_node->child1())), unsure(isCellPath), unsure(slowPath));

@@class LowerDFGToB3 {
87198719 LBasicBlock rightIsNotBigInt32 = m_out.newBlock();
87208720 LBasicBlock continuation = m_out.newBlock();
87218721
8722  FTL_TYPE_CHECK(jsValueValue(left), m_node->child1(), ~SpecFullNumber, isNumber(left));
8723  FTL_TYPE_CHECK(jsValueValue(right), m_node->child2(), ~SpecFullNumber, isNumber(right));
8724 
87258722 // Inserts a check that a value is a HeapBigInt, assuming only that we know it is not a BigInt32
87268723 auto checkIsHeapBigInt = [&](LValue lowValue, Edge highValue) {
87278724 if (m_interpreter.needsTypeCheck(highValue, SpecHeapBigInt)) {

@@class LowerDFGToB3 {
87318728 }
87328729 };
87338730
8734  m_out.branch(isBigInt32KnownNotNumber(left, provenType(m_node->child1())), unsure(leftIsBigInt32), unsure(leftIsNotBigInt32));
 8731 m_out.branch(isBigInt32(left, provenType(m_node->child1())), unsure(leftIsBigInt32), unsure(leftIsNotBigInt32));
87358732
87368733 LBasicBlock lastNext = m_out.appendTo(leftIsBigInt32, bothAreBigInt32);
8737  m_out.branch(isBigInt32KnownNotNumber(right, provenType(m_node->child2())), unsure(bothAreBigInt32), unsure(onlyLeftIsBigInt32));
 8734 m_out.branch(isBigInt32(right, provenType(m_node->child2())), unsure(bothAreBigInt32), unsure(onlyLeftIsBigInt32));
87388735
87398736 m_out.appendTo(bothAreBigInt32, onlyLeftIsBigInt32);
87408737 ValueFromBlock resultBothAreBigInt32 = m_out.anchor(m_out.equal(left, right));

@@class LowerDFGToB3 {
87558752 m_out.jump(continuation);
87568753
87578754 m_out.appendTo(leftIsHeapBigInt, rightIsBigInt32);
8758  m_out.branch(isBigInt32KnownNotNumber(right, provenType(m_node->child2())), unsure(rightIsBigInt32), unsure(rightIsNotBigInt32));
 8755 m_out.branch(isBigInt32(right, provenType(m_node->child2())), unsure(rightIsBigInt32), unsure(rightIsNotBigInt32));
87598756
87608757 m_out.appendTo(rightIsBigInt32, rightIsNotBigInt32);
87618758 LValue unboxedRight = unboxBigInt32(right);

@@class LowerDFGToB3 {
1092810925
1092910926 LBasicBlock lastNext = m_out.appendTo(isNotCellCase, isCellCase);
1093010927 // FIXME: we should filter the provenType to include the fact that we know we are not dealing with a cell
10931  ValueFromBlock notCellResult = m_out.anchor(isBigInt32KnownNotCell(value, provenType(m_node->child1())));
 10928 ValueFromBlock notCellResult = m_out.anchor(isBigInt32(value, provenType(m_node->child1())));
1093210929 m_out.jump(continuation);
1093310930
1093410931 m_out.appendTo(isCellCase, continuation);

@@class LowerDFGToB3 {
1547115468#if USE(BIGINT32)
1547215469 m_out.appendTo(notDoubleCase, bigInt32Case);
1547315470 m_out.branch(
15474  isBigInt32KnownNotNumber(value, provenType(edge) & ~SpecCell),
 15471 isBigInt32(value, provenType(edge) & ~SpecCell),
1547515472 unsure(bigInt32Case), unsure(notBigInt32Case));
1547615473
1547715474 m_out.appendTo(bigInt32Case, notBigInt32Case);

@@class LowerDFGToB3 {
1619716194
1619816195#if USE(BIGINT32)
1619916196 m_out.appendTo(notNumberCase, notBigInt32Case);
16200  m_out.branch(isBigInt32KnownNotNumber(value, provenType(child) & ~SpecCell), unsure(bigIntCase), unsure(notBigInt32Case));
 16197 m_out.branch(isBigInt32(value, provenType(child) & ~SpecCell), unsure(bigIntCase), unsure(notBigInt32Case));
1620116198
1620216199 m_out.appendTo(notBigInt32Case, notNullCase);
1620316200#else

@@class LowerDFGToB3 {
1691716914 LoweredNodeValue value = m_jsValueValues.get(edge.node());
1691816915 if (isValid(value)) {
1691916916 LValue result = value.value();
16920  FTL_TYPE_CHECK(jsValueValue(result), edge, ~SpecFullNumber, isNumber(result));
16921  FTL_TYPE_CHECK(jsValueValue(result), edge, SpecBigInt32, isNotBigInt32KnownNotNumber(result));
 16917 FTL_TYPE_CHECK(jsValueValue(result), edge, SpecBigInt32, isNotBigInt32(result));
1692216918 return result;
1692316919 }
1692416920

@@class LowerDFGToB3 {
1711517111 }
1711617112
1711717113#if USE(BIGINT32)
17118  LValue isBigInt32KnownNotCell(LValue jsValue, SpeculatedType type = SpecFullTop)
 17114 LValue isBigInt32(LValue jsValue, SpeculatedType type = SpecFullTop)
1711917115 {
1712017116 if (LValue proven = isProvenValue(type, SpecBigInt32))
1712117117 return proven;
1712217118 return m_out.equal(m_out.bitAnd(jsValue, m_out.constInt64(JSValue::BigInt32Mask)), m_out.constInt64(JSValue::BigInt32Tag));
1712317119 }
17124  LValue isBigInt32KnownNotNumber(LValue jsValue, SpeculatedType type = SpecFullTop)
17125  {
17126  if (LValue proven = isProvenValue(type, SpecBigInt32))
17127  return proven;
17128  return m_out.equal(m_out.bitAnd(jsValue, m_out.constInt64(JSValue::BigInt32Tag)), m_out.constInt64(JSValue::BigInt32Tag));
17129  }
17130  LValue isNotBigInt32KnownNotNumber(LValue jsValue, SpeculatedType type = SpecFullTop)
 17120 LValue isNotBigInt32(LValue jsValue, SpeculatedType type = SpecFullTop)
1713117121 {
1713217122 if (LValue proven = isProvenValue(type, ~SpecBigInt32))
1713317123 return proven;
17134  return m_out.notEqual(m_out.bitAnd(jsValue, m_out.constInt64(JSValue::BigInt32Tag)), m_out.constInt64(JSValue::BigInt32Tag));
 17124 return m_out.notEqual(m_out.bitAnd(jsValue, m_out.constInt64(JSValue::BigInt32Mask)), m_out.constInt64(JSValue::BigInt32Tag));
1713517125 }
1713617126 LValue unboxBigInt32(LValue jsValue)
1713717127 {

@@class LowerDFGToB3 {
1714317133 m_out.shl(m_out.zeroExt(int32Value, B3::Int64), m_out.constInt64(16)),
1714417134 m_out.constInt64(JSValue::BigInt32Tag));
1714517135 }
17146  LValue isNotAnyBigIntKnownNotNumber(LValue jsValue, SpeculatedType type = SpecFullTop)
 17136 LValue isNotAnyBigInt(LValue jsValue, SpeculatedType type = SpecFullTop)
1714717137 {
1714817138 if (LValue proven = isProvenValue(type, ~SpecBigInt))
1714917139 return proven;

@@class LowerDFGToB3 {
1715917149 LBasicBlock isCellCase = m_out.newBlock();
1716017150 LBasicBlock continuation = m_out.newBlock();
1716117151
17162  m_out.branch(isBigInt32KnownNotNumber(jsValue, type), unsure(isBigInt32Case), unsure(isNotBigInt32Case));
 17152 m_out.branch(isBigInt32(jsValue, type), unsure(isBigInt32Case), unsure(isNotBigInt32Case));
1716317153
1716417154 LBasicBlock lastNext = m_out.appendTo(isBigInt32Case, isNotBigInt32Case);
1716517155 ValueFromBlock returnFalse = m_out.anchor(m_out.booleanFalse);

@@class LowerDFGToB3 {
1819018180 void speculateBigInt32(Edge edge)
1819118181 {
1819218182 LValue value = lowJSValue(edge, ManualOperandSpeculation);
18193  FTL_TYPE_CHECK(jsValueValue(value), edge, ~SpecFullNumber, isNumber(value));
18194  FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBigInt32, isNotBigInt32KnownNotNumber(value));
 18183 FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBigInt32, isNotBigInt32(value));
1819518184 }
1819618185
1819718186 void speculateAnyBigInt(Edge edge)
1819818187 {
1819918188 LValue value = lowJSValue(edge, ManualOperandSpeculation);
18200  FTL_TYPE_CHECK(jsValueValue(value), edge, ~SpecFullNumber, isNumber(value));
18201  FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBigInt, isNotAnyBigIntKnownNotNumber(value));
 18189 FTL_TYPE_CHECK(jsValueValue(value), edge, SpecBigInt, isNotAnyBigInt(value));
1820218190 }
1820318191#endif
1820418192

Source/JavaScriptCore/jit/AssemblyHelpers.cpp

@@void AssemblyHelpers::emitConvertValueToBoolean(VM& vm, JSValueRegs value, GPRRe
755755
756756 notDouble.link(this);
757757#if USE(BIGINT32)
758  auto isNotBigInt32 = branchIfNotBigInt32KnownNotNumber(value.gpr(), result);
 758 auto isNotBigInt32 = branchIfNotBigInt32(value.gpr(), result);
759759 move(value.gpr(), result);
760760 urshift64(TrustedImm32(16), result);
761761 compare32(invert ? Equal : NotEqual, result, TrustedImm32(0), result);

@@AssemblyHelpers::JumpList AssemblyHelpers::branchIfValue(VM& vm, JSValueRegs val
856856
857857 notDouble.link(this);
858858#if USE(BIGINT32)
859  auto isNotBigInt32 = branchIfNotBigInt32KnownNotNumber(value.gpr(), scratch);
 859 auto isNotBigInt32 = branchIfNotBigInt32(value.gpr(), scratch);
860860 move(value.gpr(), scratch);
861861 urshift64(TrustedImm32(16), scratch);
862862 truthy.append(branchTest32(invert ? Zero : NonZero, scratch));

Source/JavaScriptCore/jit/AssemblyHelpers.h

@@class AssemblyHelpers : public MacroAssembler {
931931 }
932932
933933#if USE(BIGINT32)
934  Jump branchIfBigInt32(GPRReg gpr, GPRReg tempGPR, TagRegistersMode mode = HaveTagRegisters)
935  {
936  Jump number = branchIfNumber(gpr, mode);
937  Jump bigInt32 = branchIfBigInt32KnownNotNumber(gpr, tempGPR);
938  number.link(this);
939  return bigInt32;
940  }
941  JumpList branchIfNotBigInt32(GPRReg gpr, GPRReg tempGPR, TagRegistersMode mode = HaveTagRegisters)
942  {
943  JumpList result;
944  result.append(branchIfNumber(gpr, mode));
945  Jump bigInt32 = branchIfBigInt32KnownNotNumber(gpr, tempGPR);
946  result.append(jump());
947  bigInt32.link(this);
948  return result;
949  }
950 
951  Jump branchIfBigInt32KnownNotNumber(GPRReg gpr, GPRReg tempGPR)
 934 Jump branchIfBigInt32(GPRReg gpr, GPRReg tempGPR)
952935 {
953936 ASSERT(tempGPR != InvalidGPRReg);
954937 move(gpr, tempGPR);
955  and64(TrustedImm32(JSValue::BigInt32Tag), tempGPR);
 938 and64(TrustedImm64(JSValue::BigInt32Mask), tempGPR);
956939 return branch64(Equal, tempGPR, TrustedImm32(JSValue::BigInt32Tag));
957940 }
958  Jump branchIfNotBigInt32KnownNotNumber(JSValueRegs regs, GPRReg tempGPR)
959  {
960  return branchIfNotBigInt32KnownNotNumber(regs.gpr(), tempGPR);
961  }
962  Jump branchIfNotBigInt32KnownNotNumber(GPRReg gpr, GPRReg tempGPR)
 941 Jump branchIfNotBigInt32(GPRReg gpr, GPRReg tempGPR)
963942 {
964943 ASSERT(tempGPR != InvalidGPRReg);
965944 move(gpr, tempGPR);
966  and64(TrustedImm32(JSValue::BigInt32Tag), tempGPR);
 945 and64(TrustedImm64(JSValue::BigInt32Mask), tempGPR);
967946 return branch64(NotEqual, tempGPR, TrustedImm32(JSValue::BigInt32Tag));
968947 }
 948 Jump branchIfBigInt32(JSValueRegs regs, GPRReg tempGPR)
 949 {
 950 return branchIfBigInt32(regs.gpr(), tempGPR);
 951 }
 952 Jump branchIfNotBigInt32(JSValueRegs regs, GPRReg tempGPR)
 953 {
 954 return branchIfNotBigInt32(regs.gpr(), tempGPR);
 955 }
969956#endif // USE(BIGINT32)
970957
971958 // FIXME: rename these to make it clear that they require their input to be a cell.

@@class AssemblyHelpers : public MacroAssembler {
18331820 notBoolean.link(this);
18341821
18351822#if USE(BIGINT32)
1836  Jump notBigInt32 = branchIfNotBigInt32KnownNotNumber(regs, tempGPR);
 1823 Jump notBigInt32 = branchIfNotBigInt32(regs, tempGPR);
18371824 functor(TypeofType::BigInt, false);
18381825 notBigInt32.link(this);
18391826#endif

JSTests/ChangeLog

 12020-04-22 Yusuke Suzuki <ysuzuki@apple.com>
 2
 3 [JSC] branchIfBigInt32 can use BigInt32Mask and remove branchIfNumber filter
 4 https://bugs.webkit.org/show_bug.cgi?id=210870
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * stress/anybigintuse-should-filter-number-correctly.js: Added.
 9 (shouldBe):
 10 (test):
 11
1122020-04-22 Yusuke Suzuki <ysuzuki@apple.com>
213
314 [JSC] JSBigInt inc operation does not produce right HeapBigInt zero

JSTests/stress/anybigintuse-should-filter-number-correctly.js

 1function shouldBe(actual, expected) {
 2 if (actual !== expected)
 3 throw new Error('bad value: ' + actual);
 4}
 5
 6function test(a, b)
 7{
 8 return a === b;
 9}
 10noInline(test);
 11
 12for (var i = 0; i < 1e6; ++i) {
 13 if (i & 1) {
 14 test(0n, 0n);
 15 test(0n, 10n);
 16 } else {
 17 test(100000000000000000000000000000000000000000n, 200n);
 18 test(100000000000000000000000000000000000000000n, 100000000000000000000000000000000000000000n);
 19 }
 20}
 21shouldBe(test(20, 20), true);
 22shouldBe(test(20, 40), false);
 23shouldBe(test(0.5, 0.5), true);
 24shouldBe(test(0.5, 0.24), false);
 25shouldBe(test(20.1 - 0.1, 20), true);