diff options
author | Brian Smith <brian@dbsoft.org> | 2023-09-17 04:23:57 -0500 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2023-09-20 03:33:41 +0200 |
commit | 80ae8aec7cf0e08467aadad6087710afeef36b40 (patch) | |
tree | 57aa428a751bdf45733ed1102a091133b0506c37 | |
parent | d8441d7c8175608835f3b56a76666f48e4da0548 (diff) | |
download | uxp-80ae8aec7cf0e08467aadad6087710afeef36b40.tar.gz |
Issue #2308 & #1240 Follow-up - Add BigInt support to JSOP_INC and JSOP_DEC.
https://bugzilla.mozilla.org/show_bug.cgi?id=1526309
-rw-r--r-- | js/public/TrackedOptimizationInfo.h | 5 | ||||
-rw-r--r-- | js/src/jit/IonBuilder.cpp | 201 | ||||
-rw-r--r-- | js/src/jit/IonBuilder.h | 11 | ||||
-rw-r--r-- | js/src/jit/MIR.cpp | 17 | ||||
-rw-r--r-- | js/src/jit/MIR.h | 1 | ||||
-rw-r--r-- | js/src/vm/BigIntType.cpp | 143 | ||||
-rw-r--r-- | js/src/vm/BigIntType.h | 10 | ||||
-rw-r--r-- | js/src/vm/Interpreter-inl.h | 22 |
8 files changed, 283 insertions, 127 deletions
diff --git a/js/public/TrackedOptimizationInfo.h b/js/public/TrackedOptimizationInfo.h index ce3508cd68..ebaf5915cd 100644 --- a/js/public/TrackedOptimizationInfo.h +++ b/js/public/TrackedOptimizationInfo.h @@ -57,6 +57,10 @@ namespace JS { _(BinaryArith_SharedCache) \ _(BinaryArith_Call) \ \ + _(UnaryArith_SpecializedTypes) \ + _(UnaryArith_SpecializedOnBaselineTypes) \ + _(UnaryArith_InlineCache) \ + \ _(InlineCache_OptimizedStub) \ \ _(Call_Inline) @@ -112,6 +116,7 @@ namespace JS { _(GetElemStringNotCached) \ _(NonNativeReceiver) \ _(IndexType) \ + _(SpeculationOnInputTypesFailed) \ _(SetElemNonDenseNonTANotCached) \ _(NoSimdJitSupport) \ _(SimdTypeNotOptimized) \ diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 2134d1b613..fdbdb55bd8 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -4858,7 +4858,7 @@ IonBuilder::jsop_bitop(JSOp op) } MDefinition::Opcode -JSOpToMDefinition(JSOp op) +BinaryJSOpToMDefinition(JSOp op) { switch (op) { case JSOP_ADD: @@ -4959,6 +4959,40 @@ IonBuilder::powTrySpecialized(bool* emitted, MDefinition* base, MDefinition* pow return true; } +MIRType +IonBuilder::binaryArithNumberSpecialization(MDefinition* left, MDefinition* right) +{ + // Try to specialize as int32. + if (left->type() == MIRType::Int32 && right->type() == MIRType::Int32 && + !inspector->hasSeenDoubleResult(pc)) { + return MIRType::Int32; + } + return MIRType::Double; +} + +MBinaryArithInstruction* +IonBuilder::binaryArithEmitSpecialized(MDefinition::Opcode op, MIRType specialization, + MDefinition* left, MDefinition* right) +{ + MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), op, left, right); + ins->setSpecialization(specialization); + + if (op == MDefinition::Op_Add || op == MDefinition::Op_Mul) { + ins->setCommutative(); + } + + current->add(ins); + current->push(ins); + + MOZ_ASSERT(!ins->isEffectful()); + + if(!maybeInsertResume()) { + return nullptr; + } + + return ins; +} + static inline bool SimpleArithOperand(MDefinition* op) { @@ -4992,19 +5026,20 @@ IonBuilder::binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left, return true; } - MDefinition::Opcode defOp = JSOpToMDefinition(op); - MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), defOp, left, right); - ins->setNumberSpecialization(alloc(), inspector, pc); - - if (op == JSOP_ADD || op == JSOP_MUL) - ins->setCommutative(); - - current->add(ins); - current->push(ins); + MDefinition::Opcode defOp = BinaryJSOpToMDefinition(op); + MIRType specialization = binaryArithNumberSpecialization(left, right); + MBinaryArithInstruction* ins = binaryArithEmitSpecialized(defOp, specialization, left, right); - MOZ_ASSERT(!ins->isEffectful()); - if (!maybeInsertResume()) + if(!ins) { return false; + } + + // Relax int32 to double if, despite the fact that we have int32 operands and + // we've never seen a double result, we know the result may overflow or be a + // double. + if (specialization == MIRType::Int32 && ins->constantDoubleResult(alloc())) { + ins->setSpecialization(MIRType::Double); + } trackOptimizationSuccess(); *emitted = true; @@ -5028,16 +5063,10 @@ IonBuilder::binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, return true; } - MDefinition::Opcode def_op = JSOpToMDefinition(op); - MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), def_op, left, right); - ins->setSpecialization(specialization); - - current->add(ins); - current->push(ins); - - MOZ_ASSERT(!ins->isEffectful()); - if (!maybeInsertResume()) + MDefinition::Opcode defOp = BinaryJSOpToMDefinition(op); + if(!binaryArithEmitSpecialized(defOp, specialization, left, right)) { return false; + } trackOptimizationSuccess(); *emitted = true; @@ -5076,14 +5105,6 @@ IonBuilder::arithTrySharedStub(bool* emitted, JSOp op, stub = MUnarySharedStub::New(alloc(), right); break; - case JSOP_INC: - MOZ_ASSERT(op == JSOP_ADD && right->toConstant()->toInt32() == 1); - stub = MUnarySharedStub::New(alloc(), left); - break; - case JSOP_DEC: - MOZ_ASSERT(op == JSOP_SUB && right->toConstant()->toInt32() == 1); - stub = MUnarySharedStub::New(alloc(), left); - break; case JSOP_ADD: case JSOP_SUB: case JSOP_MUL: @@ -5138,8 +5159,8 @@ IonBuilder::jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right) trackOptimizationAttempt(TrackedStrategy::BinaryArith_Call); trackOptimizationSuccess(); - MDefinition::Opcode def_op = JSOpToMDefinition(op); - MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), def_op, left, right); + MDefinition::Opcode defOp = BinaryJSOpToMDefinition(op); + MBinaryArithInstruction* ins = MBinaryArithInstruction::New(alloc(), defOp, left, right); // Decrease type from 'any type' to 'empty type' when one of the operands // is 'empty typed'. @@ -5216,27 +5237,117 @@ IonBuilder::jsop_neg() return jsop_binary_arith(JSOP_MUL, negator, right); } +MDefinition* +IonBuilder::unaryArithConvertToBinary(JSOp op, MDefinition::Opcode* defOp) +{ + switch (op) { + case JSOP_INC: { + *defOp = MDefinition::Op_Add; + MConstant* right = MConstant::New(alloc(), Int32Value(1)); + current->add(right); + return right; + } + case JSOP_DEC: { + *defOp = MDefinition::Op_Sub; + MConstant* right = MConstant::New(alloc(), Int32Value(1)); + current->add(right); + return right; + } + default: + MOZ_CRASH("unexpected unary opcode"); + } +} + bool -IonBuilder::jsop_inc_or_dec(JSOp op) +IonBuilder::unaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* value) { - // As above, pass constant without slot traffic. - MConstant* one = MConstant::New(alloc(), Int32Value(1)); - current->add(one); + MOZ_ASSERT(*emitted == false); + // Try to convert Inc(x) or Dec(x) to Add(x,1) or Sub(x,1) if the operand is a + // number. + + trackOptimizationAttempt(TrackedStrategy::UnaryArith_SpecializedTypes); + + if (!IsNumberType(value->type())) { + trackOptimizationOutcome(TrackedOutcome::OperandNotNumber); + return true; + } + + MDefinition::Opcode defOp; + MDefinition* rhs = unaryArithConvertToBinary(op, &defOp); + MIRType specialization = binaryArithNumberSpecialization(value, rhs); + if (!binaryArithEmitSpecialized(defOp, specialization, value, rhs)) { + return false; + } + + trackOptimizationSuccess(); + *emitted = true; + return true; +} + +bool +IonBuilder::unaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* value) +{ + MOZ_ASSERT(*emitted == false); + + // Try to emit a specialized binary instruction speculating the + // type using the baseline caches. + + trackOptimizationAttempt(TrackedStrategy::UnaryArith_SpecializedOnBaselineTypes); + + MIRType specialization = inspector->expectedBinaryArithSpecialization(pc); + if (specialization == MIRType::None) { + trackOptimizationOutcome(TrackedOutcome::SpeculationOnInputTypesFailed); + return true; + } + + MDefinition::Opcode defOp; + MDefinition* rhs = unaryArithConvertToBinary(op, &defOp); + if (!binaryArithEmitSpecialized(defOp, specialization, value, rhs)) { + return false; + } + + trackOptimizationSuccess(); + *emitted = true; + return true; +} + +bool +IonBuilder::jsop_inc_or_dec(JSOp op) +{ + bool emitted = false; MDefinition* value = current->pop(); - switch (op) { - case JSOP_INC: - op = JSOP_ADD; - break; - case JSOP_DEC: - op = JSOP_SUB; - break; - default: - MOZ_CRASH("jsop_inc_or_dec with bad op"); + startTrackingOptimizations(); + + trackTypeInfo(TrackedTypeSite::Operand, value->type(), value->resultTypeSet()); + + if (!unaryArithTrySpecialized(&emitted, op, value)) { + return false; } + if (emitted) { + return true; + } + + if (!unaryArithTrySpecializedOnBaselineInspector(&emitted, op, value)) { + return false; + } + if (emitted) { + return true; + } + + trackOptimizationAttempt(TrackedStrategy::UnaryArith_InlineCache); + trackOptimizationSuccess(); + + MInstruction* stub = MUnarySharedStub::New(alloc(), value); + current->add(stub); + current->push(stub); + + // Decrease type from 'any type' to 'empty type' when one of the operands + // is 'empty typed'. + maybeMarkEmpty(stub); - return jsop_binary_arith(op, value, one); + return resumeAfter(stub); } bool diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 162edb36f2..f12a24bcfc 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -497,8 +497,13 @@ class IonBuilder // jsop_binary_arith helpers. MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left, MDefinition* right); + MIRType binaryArithNumberSpecialization(MDefinition* left, MDefinition* right); MOZ_MUST_USE bool binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); + MOZ_MUST_USE MBinaryArithInstruction* binaryArithEmitSpecialized(MDefinition::Opcode op, + MIRType specialization, + MDefinition* left, + MDefinition* right); MOZ_MUST_USE bool binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right); MOZ_MUST_USE bool binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, @@ -510,6 +515,12 @@ class IonBuilder // jsop_bitnot helpers. MOZ_MUST_USE bool bitnotTrySpecialized(bool* emitted, MDefinition* input); + // jsop_inc_or_dec helpers. + MDefinition* unaryArithConvertToBinary(JSOp op, MDefinition::Opcode* defOp); + MOZ_MUST_USE bool unaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* value); + MOZ_MUST_USE bool unaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, + MDefinition* value); + // jsop_pow helpers. MOZ_MUST_USE bool powTrySpecialized(bool* emitted, MDefinition* base, MDefinition* power, MIRType outputType); diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 2264bed4f2..05e37cdc6a 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -3110,23 +3110,6 @@ MBinaryArithInstruction::New(TempAllocator& alloc, Opcode op, } } -void -MBinaryArithInstruction::setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, - jsbytecode* pc) -{ - setSpecialization(MIRType::Double); - - // Try to specialize as int32. - if (getOperand(0)->type() == MIRType::Int32 && getOperand(1)->type() == MIRType::Int32) { - bool seenDouble = inspector->hasSeenDoubleResult(pc); - - // Use int32 specialization if the operation doesn't overflow on its - // constant operands and if the operation has never overflowed. - if (!seenDouble && !constantDoubleResult(alloc)) - setInt32Specialization(); - } -} - bool MBinaryArithInstruction::constantDoubleResult(TempAllocator& alloc) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 72c5214845..327310122c 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -6219,7 +6219,6 @@ class MBinaryArithInstruction specialization_ = MIRType::Int32; setResultType(MIRType::Int32); } - void setNumberSpecialization(TempAllocator& alloc, BaselineInspector* inspector, jsbytecode* pc); virtual void trySpecializeFloat32(TempAllocator& alloc) override; diff --git a/js/src/vm/BigIntType.cpp b/js/src/vm/BigIntType.cpp index 8382c641fa..1f8b061e02 100644 --- a/js/src/vm/BigIntType.cpp +++ b/js/src/vm/BigIntType.cpp @@ -185,16 +185,21 @@ BigInt* BigInt::zero(ExclusiveContext* cx) { return createUninitialized(cx, 0, false); } -BigInt* BigInt::one(ExclusiveContext* cx) { - BigInt* ret = createUninitialized(cx, 1, false); - - if (!ret) { +BigInt* BigInt::createFromDigit(ExclusiveContext* cx, Digit d, bool isNegative) { + MOZ_ASSERT(d != 0); + BigInt* res = createUninitialized(cx, 1, isNegative); + if (!res) { return nullptr; } - ret->setDigit(0, 1); + res->setDigit(0, d); + return res; +} - return ret; +BigInt* BigInt::one(ExclusiveContext* cx) { return createFromDigit(cx, 1, false); } + +BigInt* BigInt::negativeOne(ExclusiveContext* cx) { + return createFromDigit(cx, 1, true); } BigInt* BigInt::neg(ExclusiveContext* cx, HandleBigInt x) { @@ -977,21 +982,26 @@ BigInt* BigInt::absoluteAddOne(ExclusiveContext* cx, HandleBigInt x, return destructivelyTrimHighZeroDigits(cx, result); } -// Like the above, but you can specify that the allocated result should have -// length `resultLength`, which must be at least as large as `x->digitLength()`. -// The result will be unsigned. BigInt* BigInt::absoluteSubOne(ExclusiveContext* cx, HandleBigInt x, - unsigned resultLength) { + bool resultNegative) { MOZ_ASSERT(!x->isZero()); - MOZ_ASSERT(resultLength >= x->digitLength()); - bool resultNegative = false; - RootedBigInt result(cx, - createUninitialized(cx, resultLength, resultNegative)); + + unsigned length = x->digitLength(); + + if (length == 1) { + Digit d = x->digit(0); + if (d == 1) { + // Ignore resultNegative. + return zero(cx); + } + return createFromDigit(cx, d - 1, resultNegative); + } + + RootedBigInt result(cx, createUninitialized(cx, length, resultNegative)); if (!result) { return nullptr; } - unsigned length = x->digitLength(); Digit borrow = 1; for (unsigned i = 0; i < length; i++) { Digit newBorrow = 0; @@ -999,13 +1009,36 @@ BigInt* BigInt::absoluteSubOne(ExclusiveContext* cx, HandleBigInt x, borrow = newBorrow; } MOZ_ASSERT(!borrow); - for (unsigned i = length; i < resultLength; i++) { - result->setDigit(i, 0); - } return destructivelyTrimHighZeroDigits(cx, result); } +BigInt* BigInt::inc(ExclusiveContext* cx, HandleBigInt x) { + if (x->isZero()) { + return one(cx); + } + + bool isNegative = x->isNegative(); + if (isNegative) { + return absoluteSubOne(cx, x, isNegative); + } + + return absoluteAddOne(cx, x, isNegative); +} + +BigInt* BigInt::dec(ExclusiveContext* cx, HandleBigInt x) { + if (x->isZero()) { + return negativeOne(cx); + } + + bool isNegative = x->isNegative(); + if (isNegative) { + return absoluteAddOne(cx, x, isNegative); + } + + return absoluteSubOne(cx, x, isNegative); +} + // Lookup table for the maximum number of bits required per character of a // base-N string representation of a number. To increase accuracy, the array // value is the actual value multiplied by 32. To generate this table: @@ -1569,13 +1602,7 @@ BigInt* BigInt::createFromUint64(ExclusiveContext* cx, uint64_t n) { return res; } - BigInt* res = createUninitialized(cx, 1, isNegative); - if (!res) { - return nullptr; - } - - res->setDigit(0, n); - return res; + return createFromDigit(cx, n, isNegative); } BigInt* BigInt::createFromInt64(ExclusiveContext* cx, int64_t n) { @@ -1770,12 +1797,7 @@ BigInt* BigInt::mod(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) { return zero(cx); } - BigInt* remainder = createUninitialized(cx, 1, x->isNegative()); - if (!remainder) { - return nullptr; - } - remainder->setDigit(0, remainderDigit); - return remainder; + return createFromDigit(cx, remainderDigit, x->isNegative()); } else { RootedBigInt remainder(cx); if (!absoluteDivWithBigIntDivisor(cx, x, y, Nothing(), Some(&remainder), @@ -1930,15 +1952,7 @@ BigInt* BigInt::lshByAbsolute(ExclusiveContext* cx, HandleBigInt x, HandleBigInt } BigInt* BigInt::rshByMaximum(ExclusiveContext* cx, bool isNegative) { - if (isNegative) { - RootedBigInt negativeOne(cx, createUninitialized(cx, 1, isNegative)); - if (!negativeOne) { - return nullptr; - } - negativeOne->setDigit(0, 1); - return negativeOne; - } - return zero(cx); + return isNegative ? negativeOne(cx) : zero(cx); } BigInt* BigInt::rshByAbsolute(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) { @@ -2049,14 +2063,13 @@ BigInt* BigInt::bitAnd(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) { } if (x->isNegative() && y->isNegative()) { - int resultLength = std::max(x->digitLength(), y->digitLength()) + 1; // (-x) & (-y) == ~(x-1) & ~(y-1) == ~((x-1) | (y-1)) // == -(((x-1) | (y-1)) + 1) - RootedBigInt x1(cx, absoluteSubOne(cx, x, resultLength)); + RootedBigInt x1(cx, absoluteSubOne(cx, x)); if (!x1) { return nullptr; } - RootedBigInt y1(cx, absoluteSubOne(cx, y, y->digitLength())); + RootedBigInt y1(cx, absoluteSubOne(cx, y)); if (!y1) { return nullptr; } @@ -2072,7 +2085,7 @@ BigInt* BigInt::bitAnd(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) { HandleBigInt& pos = x->isNegative() ? y : x; HandleBigInt& neg = x->isNegative() ? x : y; - RootedBigInt neg1(cx, absoluteSubOne(cx, neg, neg->digitLength())); + RootedBigInt neg1(cx, absoluteSubOne(cx, neg)); if (!neg1) { return nullptr; } @@ -2096,27 +2109,24 @@ BigInt* BigInt::bitXor(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) { } if (x->isNegative() && y->isNegative()) { - int resultLength = std::max(x->digitLength(), y->digitLength()); - // (-x) ^ (-y) == ~(x-1) ^ ~(y-1) == (x-1) ^ (y-1) - RootedBigInt x1(cx, absoluteSubOne(cx, x, resultLength)); + RootedBigInt x1(cx, absoluteSubOne(cx, x)); if (!x1) { return nullptr; } - RootedBigInt y1(cx, absoluteSubOne(cx, y, y->digitLength())); + RootedBigInt y1(cx, absoluteSubOne(cx, y)); if (!y1) { return nullptr; } return absoluteXor(cx, x1, y1); } MOZ_ASSERT(x->isNegative() != y->isNegative()); - int resultLength = std::max(x->digitLength(), y->digitLength()) + 1; HandleBigInt& pos = x->isNegative() ? y : x; HandleBigInt& neg = x->isNegative() ? x : y; // x ^ (-y) == x ^ ~(y-1) == ~(x ^ (y-1)) == -((x ^ (y-1)) + 1) - RootedBigInt result(cx, absoluteSubOne(cx, neg, resultLength)); + RootedBigInt result(cx, absoluteSubOne(cx, neg)); if (!result) { return nullptr; } @@ -2138,7 +2148,6 @@ BigInt* BigInt::bitOr(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) { return x; } - unsigned resultLength = std::max(x->digitLength(), y->digitLength()); bool resultNegative = x->isNegative() || y->isNegative(); if (!resultNegative) { @@ -2148,11 +2157,11 @@ BigInt* BigInt::bitOr(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) { if (x->isNegative() && y->isNegative()) { // (-x) | (-y) == ~(x-1) | ~(y-1) == ~((x-1) & (y-1)) // == -(((x-1) & (y-1)) + 1) - RootedBigInt result(cx, absoluteSubOne(cx, x, resultLength)); + RootedBigInt result(cx, absoluteSubOne(cx, x)); if (!result) { return nullptr; } - RootedBigInt y1(cx, absoluteSubOne(cx, y, y->digitLength())); + RootedBigInt y1(cx, absoluteSubOne(cx, y)); if (!y1) { return nullptr; } @@ -2168,7 +2177,7 @@ BigInt* BigInt::bitOr(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) { HandleBigInt& neg = x->isNegative() ? x : y; // x | (-y) == x | ~(y-1) == ~((y-1) &~ x) == -(((y-1) &~ x) + 1) - RootedBigInt result(cx, absoluteSubOne(cx, neg, resultLength)); + RootedBigInt result(cx, absoluteSubOne(cx, neg)); if (!result) { return nullptr; } @@ -2183,7 +2192,7 @@ BigInt* BigInt::bitOr(ExclusiveContext* cx, HandleBigInt x, HandleBigInt y) { BigInt* BigInt::bitNot(ExclusiveContext* cx, HandleBigInt x) { if (x->isNegative()) { // ~(-x) == ~(~(x-1)) == x-1 - return absoluteSubOne(cx, x, x->digitLength()); + return absoluteSubOne(cx, x); } else { // ~x == -x-1 == -(x+1) bool resultNegative = true; @@ -2535,6 +2544,30 @@ bool BigInt::neg(ExclusiveContext* cx, HandleValue operand, MutableHandleValue r return true; } +bool BigInt::inc(ExclusiveContext* cx, HandleValue operand, MutableHandleValue res) { + MOZ_ASSERT(operand.isBigInt()); + + RootedBigInt operandBigInt(cx, operand.toBigInt()); + BigInt* resBigInt = BigInt::inc(cx, operandBigInt); + if (!resBigInt) { + return false; + } + res.setBigInt(resBigInt); + return true; +} + +bool BigInt::dec(ExclusiveContext* cx, HandleValue operand, MutableHandleValue res) { + MOZ_ASSERT(operand.isBigInt()); + + RootedBigInt operandBigInt(cx, operand.toBigInt()); + BigInt* resBigInt = BigInt::dec(cx, operandBigInt); + if (!resBigInt) { + return false; + } + res.setBigInt(resBigInt); + return true; +} + bool BigInt::lsh(ExclusiveContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res) { if (!ValidBigIntOperands(cx, lhs, rhs)) { diff --git a/js/src/vm/BigIntType.h b/js/src/vm/BigIntType.h index ea0317fd9c..693f8bf36c 100644 --- a/js/src/vm/BigIntType.h +++ b/js/src/vm/BigIntType.h @@ -97,9 +97,11 @@ class BigInt final : public js::gc::TenuredCell { static BigInt* createFromDouble(js::ExclusiveContext* cx, double d); static BigInt* createFromUint64(js::ExclusiveContext* cx, uint64_t n); static BigInt* createFromInt64(js::ExclusiveContext* cx, int64_t n); + static BigInt* createFromDigit(js::ExclusiveContext* cx, Digit d, bool isNegative); // FIXME: Cache these values. static BigInt* zero(js::ExclusiveContext* cx); static BigInt* one(js::ExclusiveContext* cx); + static BigInt* negativeOne(js::ExclusiveContext* cx); static BigInt* copy(js::ExclusiveContext* cx, Handle<BigInt*> x); static BigInt* add(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y); @@ -109,6 +111,8 @@ class BigInt final : public js::gc::TenuredCell { static BigInt* mod(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y); static BigInt* pow(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y); static BigInt* neg(js::ExclusiveContext* cx, Handle<BigInt*> x); + static BigInt* inc(js::ExclusiveContext* cx, Handle<BigInt*> x); + static BigInt* dec(js::ExclusiveContext* cx, Handle<BigInt*> x); static BigInt* lsh(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y); static BigInt* rsh(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y); static BigInt* bitAnd(js::ExclusiveContext* cx, Handle<BigInt*> x, Handle<BigInt*> y); @@ -145,6 +149,10 @@ class BigInt final : public js::gc::TenuredCell { MutableHandle<Value> res); static bool neg(js::ExclusiveContext* cx, Handle<Value> operand, MutableHandle<Value> res); + static bool inc(js::ExclusiveContext* cx, Handle<Value> operand, + MutableHandle<Value> res); + static bool dec(js::ExclusiveContext* cx, Handle<Value> operand, + MutableHandle<Value> res); static bool lsh(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs, MutableHandle<Value> res); static bool rsh(js::ExclusiveContext* cx, Handle<Value> lhs, Handle<Value> rhs, @@ -288,7 +296,7 @@ class BigInt final : public js::gc::TenuredCell { // Return `(|x| - 1) * (resultNegative ? -1 : +1)`, with the precondition that // |x| != 0. static BigInt* absoluteSubOne(js::ExclusiveContext* cx, Handle<BigInt*> x, - unsigned resultLength); + bool resultNegative = false); // Return `a + b`, incrementing `*carry` if the addition overflows. static inline Digit digitAdd(Digit a, Digit b, Digit* carry) { diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 93d2672b0f..cbf3113b50 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -421,16 +421,19 @@ IncOperation(JSContext* cx, MutableHandleValue val, MutableHandleValue res) { - MOZ_ASSERT(val.isNumber(), "+1 only callable on result of JSOP_TONUMERIC"); - int32_t i; if (val.isInt32() && (i = val.toInt32()) != INT32_MAX) { res.setInt32(i + 1); return true; } - res.setNumber(val.toNumber() + 1); - return true; + if (val.isNumber()) { + res.setNumber(val.toNumber() + 1); + return true; + } + + MOZ_ASSERT(val.isBigInt(), "+1 only callable on result of JSOP_TONUMERIC"); + return BigInt::inc(cx, val, res); } static MOZ_ALWAYS_INLINE bool @@ -438,16 +441,19 @@ DecOperation(JSContext* cx, MutableHandleValue val, MutableHandleValue res) { - MOZ_ASSERT(val.isNumber(), "-1 only callable on result of JSOP_TONUMERIC"); - int32_t i; if (val.isInt32() && (i = val.toInt32()) != INT32_MIN) { res.setInt32(i - 1); return true; } - res.setNumber(val.toNumber() - 1); - return true; + if (val.isNumber()) { + res.setNumber(val.toNumber() - 1); + return true; + } + + MOZ_ASSERT(val.isBigInt(), "-1 only callable on result of JSOP_TONUMERIC"); + return BigInt::dec(cx, val, res); } static MOZ_ALWAYS_INLINE bool |