diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 84e793a47092..b8db737d7c77 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1474,6 +1474,21 @@ void CodeGenerator::testValueTruthy(const ValueOperand& value, masm.jump(ifTruthy); } +void CodeGenerator::visitTestBIAndBranch(LTestBIAndBranch* lir) { + Label* ifTrueLabel = getJumpLabelForBranch(lir->ifTrue()); + Label* ifFalseLabel = getJumpLabelForBranch(lir->ifFalse()); + Register input = ToRegister(lir->input()); + + if (isNextBlock(lir->ifFalse()->lir())) { + masm.branchIfBigIntIsNonZero(input, ifTrueLabel); + } else if (isNextBlock(lir->ifTrue()->lir())) { + masm.branchIfBigIntIsZero(input, ifFalseLabel); + } else { + masm.branchIfBigIntIsZero(input, ifFalseLabel); + jumpToBlock(lir->ifTrue()); + } +} + void CodeGenerator::visitTestOAndBranch(LTestOAndBranch* lir) { Label* truthy = getJumpLabelForBranch(lir->ifTruthy()); Label* falsy = getJumpLabelForBranch(lir->ifFalsy()); @@ -10248,6 +10263,14 @@ void CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir) { SetLengthFromIndex(masm, lir->index(), initLength); } +void CodeGenerator::visitNotBI(LNotBI* lir) { + Register input = ToRegister(lir->input()); + Register output = ToRegister(lir->output()); + + masm.cmp32Set(Assembler::Equal, Address(input, BigInt::offsetOfLength()), + Imm32(0), output); +} + void CodeGenerator::visitNotO(LNotO* lir) { auto* ool = new (alloc()) OutOfLineTestObjectWithLabels(); addOutOfLineCode(ool, lir->mir()); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 32a371937da1..2da50166eb6d 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -571,10 +571,6 @@ void LIRGenerator::visitTest(MTest* test) { // TestPolicy). MOZ_ASSERT(opd->type() != MIRType::String); - // BigInt is boxed in type analysis. - MOZ_ASSERT(opd->type() != MIRType::BigInt, - "BigInt should be boxed by TestPolicy"); - // Testing a constant. if (MConstant* constant = opd->maybeConstantValue()) { bool b; @@ -814,6 +810,9 @@ void LIRGenerator::visitTest(MTest* test) { add(new (alloc()) LTestI64AndBranch(useInt64Register(opd), ifTrue, ifFalse)); break; + case MIRType::BigInt: + add(new (alloc()) LTestBIAndBranch(useRegister(opd), ifTrue, ifFalse)); + break; default: MOZ_CRASH("Bad type"); } @@ -3008,13 +3007,13 @@ void LIRGenerator::visitNot(MNot* ins) { // String is converted to length of string in the type analysis phase (see // TestPolicy). MOZ_ASSERT(op->type() != MIRType::String); - MOZ_ASSERT(op->type() != MIRType::BigInt, - "BigInt should be boxed by TestPolicy"); // - boolean: x xor 1 // - int32: LCompare(x, 0) // - double: LCompare(x, 0) // - null or undefined: true + // - symbol: false + // - bigint: LNotBI(x) // - object: false if it never emulates undefined, else LNotO(x) switch (op->type()) { case MIRType::Boolean: { @@ -3042,6 +3041,9 @@ void LIRGenerator::visitNot(MNot* ins) { case MIRType::Symbol: define(new (alloc()) LInteger(0), ins); break; + case MIRType::BigInt: + define(new (alloc()) LNotBI(useRegisterAtStart(op)), ins); + break; case MIRType::Object: define(new (alloc()) LNotO(useRegister(op)), ins); break; diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp index 5dc274c8c85f..384cf3bec828 100644 --- a/js/src/jit/TypePolicy.cpp +++ b/js/src/jit/TypePolicy.cpp @@ -279,6 +279,7 @@ bool TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { case MIRType::Double: case MIRType::Float32: case MIRType::Symbol: + case MIRType::BigInt: case MIRType::Object: break; @@ -290,8 +291,7 @@ bool TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { } default: - ins->replaceOperand(0, BoxAt(alloc, ins, op)); - break; + MOZ_CRASH("Unexpected MIRType."); } return true; } diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index d0200aff268f..af77e108f51f 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -1355,7 +1355,7 @@ class LTestI64AndBranch : public LControlInstructionHelper<2, INT64_PIECES, 0> { MBasicBlock* ifFalse() const { return getSuccessor(1); } }; -// Takes in either an integer or boolean input and tests it for truthiness. +// Takes in a double input and tests it for truthiness. class LTestDAndBranch : public LControlInstructionHelper<2, 1, 0> { public: LIR_HEADER(TestDAndBranch) @@ -1372,7 +1372,7 @@ class LTestDAndBranch : public LControlInstructionHelper<2, 1, 0> { MBasicBlock* ifFalse() const { return getSuccessor(1); } }; -// Takes in either an integer or boolean input and tests it for truthiness. +// Takes in a float32 input and tests it for truthiness. class LTestFAndBranch : public LControlInstructionHelper<2, 1, 0> { public: LIR_HEADER(TestFAndBranch) @@ -1389,6 +1389,23 @@ class LTestFAndBranch : public LControlInstructionHelper<2, 1, 0> { MBasicBlock* ifFalse() const { return getSuccessor(1); } }; +// Takes in a bigint input and tests it for truthiness. +class LTestBIAndBranch : public LControlInstructionHelper<2, 1, 0> { + public: + LIR_HEADER(TestBIAndBranch) + + LTestBIAndBranch(const LAllocation& in, MBasicBlock* ifTrue, + MBasicBlock* ifFalse) + : LControlInstructionHelper(classOpcode) { + setOperand(0, in); + setSuccessor(0, ifTrue); + setSuccessor(1, ifFalse); + } + + MBasicBlock* ifTrue() { return getSuccessor(0); } + MBasicBlock* ifFalse() { return getSuccessor(1); } +}; + // Takes an object and tests it for truthiness. An object is falsy iff it // emulates |undefined|; see js::EmulatesUndefined. class LTestOAndBranch : public LControlInstructionHelper<2, 1, 1> { @@ -1884,6 +1901,18 @@ class LNotF : public LInstructionHelper<1, 1, 0> { MNot* mir() { return mir_->toNot(); } }; +// Not operation on a BigInt. +class LNotBI : public LInstructionHelper<1, 1, 0> { + public: + LIR_HEADER(NotBI) + + explicit LNotBI(const LAllocation& input) : LInstructionHelper(classOpcode) { + setOperand(0, input); + } + + MNot* mir() { return mir_->toNot(); } +}; + // Boolean complement operation on an object. class LNotO : public LInstructionHelper<1, 1, 0> { public: