Issue #2308 & #1240 Follow-up - Add BigInt support to JSOP_INC and JSOP_DEC. https://bugzilla.mozilla.org/show_bug.cgi?id=1526309

This commit is contained in:
Brian Smith 2023-09-17 04:23:57 -05:00 committed by roytam1
commit e12e377e51
8 changed files with 283 additions and 127 deletions

View file

@ -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);
MDefinition::Opcode defOp = BinaryJSOpToMDefinition(op);
MIRType specialization = binaryArithNumberSpecialization(left, right);
MBinaryArithInstruction* ins = binaryArithEmitSpecialized(defOp, specialization, left, right);
if (op == JSOP_ADD || op == JSOP_MUL)
ins->setCommutative();
current->add(ins);
current->push(ins);
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::unaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* value)
{
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)
{
// As above, pass constant without slot traffic.
MConstant* one = MConstant::New(alloc(), Int32Value(1));
current->add(one);
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;
}
return jsop_binary_arith(op, value, one);
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 resumeAfter(stub);
}
bool

View file

@ -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);

View file

@ -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)
{

View file

@ -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;