Issue #2308 & #1240 Follow-up - Introduce new increment and decrement operations. https://bugzilla.mozilla.org/show_bug.cgi?id=1508521

This commit is contained in:
Brian Smith 2023-09-16 05:38:42 -05:00 • committed by roytam1
commit 5c8a6c5bb8
13 changed files with 157 additions and 30 deletions

View file

@ -233,7 +233,7 @@ ElemOpEmitter::emitIncDec()
MOZ_ASSERT(state_ == State::Get); MOZ_ASSERT(state_ == State::Get);
JSOp binOp = isInc() ? JSOP_ADD : JSOP_SUB; JSOp incOp = isInc() ? JSOP_INC : JSOP_DEC;
if (!bce_->emit1(JSOP_POS)) { // ... N if (!bce_->emit1(JSOP_POS)) { // ... N
return false; return false;
} }
@ -242,10 +242,7 @@ ElemOpEmitter::emitIncDec()
return false; return false;
} }
} }
if (!bce_->emit1(JSOP_ONE)) { // ... N? N 1 if (!bce_->emit1(incOp)) { // ... N? N+1
return false;
}
if (!bce_->emit1(binOp)) { // ... N? N+1
return false; return false;
} }
if (isPostIncDec()) { if (isPostIncDec()) {

View file

@ -339,7 +339,7 @@ NameOpEmitter::emitIncDec()
{ {
MOZ_ASSERT(state_ == State::Start); MOZ_ASSERT(state_ == State::Start);
JSOp binOp = isInc() ? JSOP_ADD : JSOP_SUB; JSOp incOp = isInc() ? JSOP_INC : JSOP_DEC;
if (!prepareForRhs()) { // ENV? V if (!prepareForRhs()) { // ENV? V
return false; return false;
} }
@ -351,10 +351,7 @@ NameOpEmitter::emitIncDec()
return false; return false;
} }
} }
if (!bce_->emit1(JSOP_ONE)) { // ENV? N? N 1 if (!bce_->emit1(incOp)) { // ENV? N? N+1
return false;
}
if (!bce_->emit1(binOp)) { // ENV? N? N+1
return false; return false;
} }
if (isPostIncDec() && emittedBindOp()) { if (isPostIncDec() && emittedBindOp()) {

View file

@ -217,7 +217,7 @@ PropOpEmitter::emitIncDec(JSAtom* prop)
MOZ_ASSERT(state_ == State::Get); MOZ_ASSERT(state_ == State::Get);
JSOp binOp = isInc() ? JSOP_ADD : JSOP_SUB; JSOp incOp = isInc() ? JSOP_INC : JSOP_DEC;
if (!bce_->emit1(JSOP_POS)) { // ... N if (!bce_->emit1(JSOP_POS)) { // ... N
return false; return false;
@ -227,10 +227,7 @@ PropOpEmitter::emitIncDec(JSAtom* prop)
return false; return false;
} }
} }
if (!bce_->emit1(JSOP_ONE)) { // ... N? N 1 if (!bce_->emit1(incOp)) { // ... N? N+1
return false;
}
if (!bce_->emit1(binOp)) { // ... N? N+1
return false; return false;
} }
if (isPostIncDec()) { if (isPostIncDec()) {

View file

@ -1939,6 +1939,18 @@ BaselineCompiler::emit_JSOP_NEG()
return emitUnaryArith(); return emitUnaryArith();
} }
bool
BaselineCompiler::emit_JSOP_INC()
{
return emitUnaryArith();
}
bool
BaselineCompiler::emit_JSOP_DEC()
{
return emitUnaryArith();
}
bool bool
BaselineCompiler::emit_JSOP_LT() BaselineCompiler::emit_JSOP_LT()
{ {

View file

@ -243,7 +243,9 @@ namespace jit {
_(JSOP_IS_CONSTRUCTING) \ _(JSOP_IS_CONSTRUCTING) \
_(JSOP_TRY_DESTRUCTURING_ITERCLOSE) \ _(JSOP_TRY_DESTRUCTURING_ITERCLOSE) \
_(JSOP_IMPORTMETA) \ _(JSOP_IMPORTMETA) \
_(JSOP_DYNAMIC_IMPORT) _(JSOP_DYNAMIC_IMPORT) \
_(JSOP_INC) \
_(JSOP_DEC)
class BaselineCompiler : public BaselineCompilerSpecific class BaselineCompiler : public BaselineCompilerSpecific
{ {
@ -327,7 +329,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
OPCODE_LIST(EMIT_OP) OPCODE_LIST(EMIT_OP)
#undef EMIT_OP #undef EMIT_OP
// JSOP_NEG, JSOP_BITNOT // JSOP_NEG, JSOP_BITNOT, JSOP_INC, JSOP_DEC
MOZ_MUST_USE bool emitUnaryArith(); MOZ_MUST_USE bool emitUnaryArith();
// JSOP_BITXOR, JSOP_LSH, JSOP_ADD etc. // JSOP_BITXOR, JSOP_LSH, JSOP_ADD etc.

View file

@ -719,6 +719,8 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
case JSOP_DIV: case JSOP_DIV:
case JSOP_MOD: case JSOP_MOD:
case JSOP_NEG: case JSOP_NEG:
case JSOP_INC:
case JSOP_DEC:
type = inspector->expectedResultType(last); type = inspector->expectedResultType(last);
break; break;
case JSOP_BIGINT: case JSOP_BIGINT:
@ -1740,6 +1742,10 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_NEG: case JSOP_NEG:
return jsop_neg(); return jsop_neg();
case JSOP_INC:
case JSOP_DEC:
return jsop_inc_or_dec(op);
case JSOP_TOSTRING: case JSOP_TOSTRING:
return jsop_tostring(); return jsop_tostring();
@ -5070,6 +5076,14 @@ IonBuilder::arithTrySharedStub(bool* emitted, JSOp op,
stub = MUnarySharedStub::New(alloc(), right); stub = MUnarySharedStub::New(alloc(), right);
break; 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_ADD:
case JSOP_SUB: case JSOP_SUB:
case JSOP_MUL: case JSOP_MUL:
@ -5202,6 +5216,29 @@ IonBuilder::jsop_neg()
return jsop_binary_arith(JSOP_MUL, negator, right); return jsop_binary_arith(JSOP_MUL, negator, right);
} }
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);
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");
}
return jsop_binary_arith(op, value, one);
}
bool bool
IonBuilder::jsop_tostring() IonBuilder::jsop_tostring()
{ {

View file

@ -692,6 +692,7 @@ class IonBuilder
MOZ_MUST_USE bool jsop_pow(); MOZ_MUST_USE bool jsop_pow();
MOZ_MUST_USE bool jsop_pos(); MOZ_MUST_USE bool jsop_pos();
MOZ_MUST_USE bool jsop_neg(); MOZ_MUST_USE bool jsop_neg();
MOZ_MUST_USE bool jsop_inc_or_dec(JSOp op);
MOZ_MUST_USE bool jsop_tostring(); MOZ_MUST_USE bool jsop_tostring();
MOZ_MUST_USE bool jsop_setarg(uint32_t arg); MOZ_MUST_USE bool jsop_setarg(uint32_t arg);
MOZ_MUST_USE bool jsop_defvar(uint32_t index); MOZ_MUST_USE bool jsop_defvar(uint32_t index);

View file

@ -1469,21 +1469,33 @@ DoUnaryArithFallback(JSContext* cx, void* payload, ICUnaryArith_Fallback* stub_,
JSOp op = JSOp(*pc); JSOp op = JSOp(*pc);
FallbackICSpew(cx, stub, "UnaryArith(%s)", CodeName[op]); FallbackICSpew(cx, stub, "UnaryArith(%s)", CodeName[op]);
// The unary operations take a copied val because the original value is needed
// below.
RootedValue valCopy(cx, val);
switch (op) { switch (op) {
case JSOP_BITNOT: { case JSOP_BITNOT: {
RootedValue valCopy(cx, val);
if (!BitNot(cx, &valCopy, res)) { if (!BitNot(cx, &valCopy, res)) {
return false; return false;
} }
break; break;
} }
case JSOP_NEG: { case JSOP_NEG: {
// We copy val here because the original value is needed below.
RootedValue valCopy(cx, val);
if (!NegOperation(cx, script, pc, &valCopy, res)) if (!NegOperation(cx, script, pc, &valCopy, res))
return false; return false;
break; break;
} }
case JSOP_INC: {
if (!IncOperation(cx, &valCopy, res)) {
return false;
}
break;
}
case JSOP_DEC: {
if (!DecOperation(cx, &valCopy, res)) {
return false;
}
break;
}
default: default:
MOZ_CRASH("Unexpected op"); MOZ_CRASH("Unexpected op");
} }

View file

@ -1855,6 +1855,8 @@ class ICBinaryArith_DoubleWithInt32 : public ICStub
// UnaryArith // UnaryArith
// JSOP_BITNOT // JSOP_BITNOT
// JSOP_NEG // JSOP_NEG
// JSOP_INC
// JSOP_DEC
class ICUnaryArith_Fallback : public ICFallbackStub class ICUnaryArith_Fallback : public ICFallbackStub
{ {

View file

@ -4958,7 +4958,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
void twoByteOp8(TwoByteOpcodeID opcode, RegisterID rm, RegisterID reg) void twoByteOp8(TwoByteOpcodeID opcode, RegisterID rm, RegisterID reg)
{ {
m_buffer.ensureSpace(MaxInstructionSize); m_buffer.ensureSpace(MaxInstructionSize);
emitRexIf(byteRegRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm); emitRexIf(byteRegRequiresRex(reg)||byteRegRequiresRex(rm), reg, 0, rm);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
m_buffer.putByteUnchecked(opcode); m_buffer.putByteUnchecked(opcode);
registerModRM(rm, reg); registerModRM(rm, reg);
@ -4967,7 +4967,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
void twoByteOp8(TwoByteOpcodeID opcode, int32_t offset, RegisterID base, RegisterID reg) void twoByteOp8(TwoByteOpcodeID opcode, int32_t offset, RegisterID base, RegisterID reg)
{ {
m_buffer.ensureSpace(MaxInstructionSize); m_buffer.ensureSpace(MaxInstructionSize);
emitRexIf(byteRegRequiresRex(reg)|regRequiresRex(base), reg, 0, base); emitRexIf(byteRegRequiresRex(reg)||regRequiresRex(base), reg, 0, base);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
m_buffer.putByteUnchecked(opcode); m_buffer.putByteUnchecked(opcode);
memoryModRM(offset, base, reg); memoryModRM(offset, base, reg);
@ -4977,7 +4977,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
int scale, RegisterID reg) int scale, RegisterID reg)
{ {
m_buffer.ensureSpace(MaxInstructionSize); m_buffer.ensureSpace(MaxInstructionSize);
emitRexIf(byteRegRequiresRex(reg)|regRequiresRex(base)|regRequiresRex(index), emitRexIf(byteRegRequiresRex(reg)||regRequiresRex(base)||regRequiresRex(index),
reg, index, base); reg, index, base);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
m_buffer.putByteUnchecked(opcode); m_buffer.putByteUnchecked(opcode);
@ -4991,7 +4991,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
void twoByteOp8_movx(TwoByteOpcodeID opcode, RegisterID rm, RegisterID reg) void twoByteOp8_movx(TwoByteOpcodeID opcode, RegisterID rm, RegisterID reg)
{ {
m_buffer.ensureSpace(MaxInstructionSize); m_buffer.ensureSpace(MaxInstructionSize);
emitRexIf(regRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm); emitRexIf(regRequiresRex(reg)||byteRegRequiresRex(rm), reg, 0, rm);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
m_buffer.putByteUnchecked(opcode); m_buffer.putByteUnchecked(opcode);
registerModRM(rm, reg); registerModRM(rm, reg);

View file

@ -416,6 +416,40 @@ NegOperation(JSContext* cx, HandleScript script, jsbytecode* pc, MutableHandleVa
return true; return true;
} }
static MOZ_ALWAYS_INLINE bool
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;
}
static MOZ_ALWAYS_INLINE bool
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;
}
static MOZ_ALWAYS_INLINE bool static MOZ_ALWAYS_INLINE bool
ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue idval, ToIdOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue idval,
MutableHandleValue res) MutableHandleValue res)

View file

@ -4176,6 +4176,26 @@ CASE(JSOP_IS_CONSTRUCTING)
PUSH_MAGIC(JS_IS_CONSTRUCTING); PUSH_MAGIC(JS_IS_CONSTRUCTING);
END_CASE(JSOP_IS_CONSTRUCTING) END_CASE(JSOP_IS_CONSTRUCTING)
CASE(JSOP_INC)
{
ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
MutableHandleValue res = REGS.stackHandleAt(-1);
if (!IncOperation(cx, &val, res)) {
goto error;
}
}
END_CASE(JSOP_INC)
CASE(JSOP_DEC)
{
ReservedRooted<Value> val(&rootValue0, REGS.sp[-1]);
MutableHandleValue res = REGS.stackHandleAt(-1);
if (!DecOperation(cx, &val, res)) {
goto error;
}
}
END_CASE(JSOP_DEC)
CASE(JSOP_BIGINT) CASE(JSOP_BIGINT)
{ {
PUSH_COPY(script->getConst(GET_UINT32_INDEX(REGS.pc))); PUSH_COPY(script->getConst(GET_UINT32_INDEX(REGS.pc)));

View file

@ -2358,6 +2358,24 @@
* Stack: arg => rval * Stack: arg => rval
*/ \ */ \
macro(JSOP_DYNAMIC_IMPORT, 234, "call-import", NULL, 1, 1, 1, JOF_BYTE) \ macro(JSOP_DYNAMIC_IMPORT, 234, "call-import", NULL, 1, 1, 1, JOF_BYTE) \
/*
* Pops the numeric value 'val' from the stack, then pushes 'val + 1'.
*
* Category: Operators
* Type: Arithmetic Operators
* Operands:
* Stack: val => (val + 1)
*/ \
macro(JSOP_INC, 235, "inc", NULL, 1, 1, 1, JOF_BYTE) \
/*
* Pops the numeric value 'val' from the stack, then pushes 'val - 1'.
*
* Category: Operators
* Type: Arithmetic Operators
* Operands:
* Stack: val => (val - 1)
*/ \
macro(JSOP_DEC, 236, "dec", NULL, 1, 1, 1, JOF_BYTE) \
/* /*
* Pushes a BigInt constant onto the stack. * Pushes a BigInt constant onto the stack.
* Category: Literals * Category: Literals
@ -2365,14 +2383,12 @@
* Operands: uint32_t constIndex * Operands: uint32_t constIndex
* Stack: => val * Stack: => val
*/ \ */ \
macro(JSOP_BIGINT, 235, "bigint", NULL, 5, 0, 1, JOF_BIGINT) macro(JSOP_BIGINT, 237, "bigint", NULL, 5, 0, 1, JOF_BIGINT)
/* /*
* In certain circumstances it may be useful to "pad out" the opcode space to * In certain circumstances it may be useful to "pad out" the opcode space to
* a power of two. Use this macro to do so. * a power of two. Use this macro to do so.
*/ */
#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \ #define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
macro(236) \
macro(237) \
macro(238) \ macro(238) \
macro(239) \ macro(239) \
macro(240) \ macro(240) \