Bug 836373 - IonMonkey changes to compareString for the baseline jit. r=jandem

This commit is contained in:
Tom Schuster 2013-02-08 00:01:15 +01:00
Родитель 0aac10ccdb
Коммит d0e36df95e
12 изменённых файлов: 107 добавлений и 97 удалений

Просмотреть файл

@ -2866,33 +2866,7 @@ CodeGenerator::emitCompareS(LInstruction *lir, JSOp op, Register left, Register
if (!ool) if (!ool)
return false; return false;
Label notPointerEqual; masm.compareStrings(op, left, right, output, temp, ool->entry());
// Fast path for identical strings
masm.branchPtr(Assembler::NotEqual, left, right, &notPointerEqual);
masm.move32(Imm32(op == JSOP_EQ || op == JSOP_STRICTEQ), output);
masm.jump(ool->rejoin());
masm.bind(&notPointerEqual);
masm.loadPtr(Address(left, JSString::offsetOfLengthAndFlags()), output);
masm.loadPtr(Address(right, JSString::offsetOfLengthAndFlags()), temp);
Label notAtom;
// We can optimize the equality operation to a pointer compare for
// two atoms.
Imm32 atomBit(JSString::ATOM_BIT);
masm.branchTest32(Assembler::Zero, output, atomBit, &notAtom);
masm.branchTest32(Assembler::Zero, temp, atomBit, &notAtom);
masm.cmpPtr(left, right);
emitSet(JSOpToCondition(op), output);
masm.jump(ool->rejoin());
masm.bind(&notAtom);
// Strings of different length can never be equal.
masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), output);
masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), temp);
masm.branchPtr(Assembler::Equal, output, temp, ool->entry());
masm.move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), output);
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
return true; return true;
@ -3056,7 +3030,7 @@ CodeGenerator::visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir)
else else
cond = masm.testUndefined(cond, value); cond = masm.testUndefined(cond, value);
emitSet(cond, output); masm.emitSet(cond, output);
return true; return true;
} }
@ -4096,7 +4070,7 @@ CodeGenerator::visitIteratorMore(LIteratorMore *lir)
// Set output to true if props_cursor < props_end. // Set output to true if props_cursor < props_end.
masm.loadPtr(Address(output, offsetof(NativeIterator, props_end)), temp); masm.loadPtr(Address(output, offsetof(NativeIterator, props_end)), temp);
masm.cmpPtr(Address(output, offsetof(NativeIterator, props_cursor)), temp); masm.cmpPtr(Address(output, offsetof(NativeIterator, props_cursor)), temp);
emitSet(Assembler::LessThan, output); masm.emitSet(Assembler::LessThan, output);
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
return true; return true;

Просмотреть файл

@ -432,6 +432,43 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject)
} }
} }
void
MacroAssembler::compareStrings(JSOp op, Register left, Register right, Register result,
Register temp, Label *fail)
{
JS_ASSERT(IsEqualityOp(op));
Label done;
Label notPointerEqual;
// Fast path for identical strings.
branchPtr(Assembler::NotEqual, left, right, &notPointerEqual);
move32(Imm32(op == JSOP_EQ || op == JSOP_STRICTEQ), result);
jump(&done);
bind(&notPointerEqual);
loadPtr(Address(left, JSString::offsetOfLengthAndFlags()), result);
loadPtr(Address(right, JSString::offsetOfLengthAndFlags()), temp);
Label notAtom;
// Optimize the equality operation to a pointer compare for two atoms.
Imm32 atomBit(JSString::ATOM_BIT);
branchTest32(Assembler::Zero, result, atomBit, &notAtom);
branchTest32(Assembler::Zero, temp, atomBit, &notAtom);
cmpPtr(left, right);
emitSet(JSOpToCondition(op), result);
jump(&done);
bind(&notAtom);
// Strings of different length can never be equal.
rshiftPtr(Imm32(JSString::LENGTH_SHIFT), result);
rshiftPtr(Imm32(JSString::LENGTH_SHIFT), temp);
branchPtr(Assembler::Equal, result, temp, fail);
move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), result);
bind(&done);
}
void void
MacroAssembler::parCheckInterruptFlags(const Register &tempReg, MacroAssembler::parCheckInterruptFlags(const Register &tempReg,
Label *fail) Label *fail)

Просмотреть файл

@ -500,6 +500,11 @@ class MacroAssembler : public MacroAssemblerSpecific
Label *fail); Label *fail);
void initGCThing(const Register &obj, JSObject *templateObject); void initGCThing(const Register &obj, JSObject *templateObject);
// Compares two strings for equality based on the JSOP.
// This checks for identical pointers, atoms and length and fails for everything else.
void compareStrings(JSOp op, Register left, Register right, Register result,
Register temp, Label *fail);
// Checks the flags that signal that parallel code may need to interrupt or // Checks the flags that signal that parallel code may need to interrupt or
// abort. Branches to fail in that case. // abort. Branches to fail in that case.
void parCheckInterruptFlags(const Register &tempReg, void parCheckInterruptFlags(const Register &tempReg,

Просмотреть файл

@ -103,13 +103,6 @@ CodeGeneratorARM::visitTestIAndBranch(LTestIAndBranch *test)
return true; return true;
} }
void
CodeGeneratorARM::emitSet(Assembler::Condition cond, const Register &dest)
{
masm.ma_mov(Imm32(0), dest);
masm.ma_mov(Imm32(1), dest, NoSetCond, cond);
}
bool bool
CodeGeneratorARM::visitCompare(LCompare *comp) CodeGeneratorARM::visitCompare(LCompare *comp)
{ {
@ -1236,7 +1229,7 @@ CodeGeneratorARM::visitCompareD(LCompareD *comp)
Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop()); Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
masm.compareDouble(lhs, rhs); masm.compareDouble(lhs, rhs);
emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output())); masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()));
return true; return true;
} }
@ -1270,7 +1263,7 @@ CodeGeneratorARM::visitCompareB(LCompareB *lir)
masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean())); masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean()));
else else
masm.cmp32(lhs.payloadReg(), ToRegister(rhs)); masm.cmp32(lhs.payloadReg(), ToRegister(rhs));
emitSet(JSOpToCondition(mir->jsop()), output); masm.emitSet(JSOpToCondition(mir->jsop()), output);
masm.jump(&done); masm.jump(&done);
} }
@ -1322,7 +1315,7 @@ CodeGeneratorARM::visitCompareV(LCompareV *lir)
masm.j(Assembler::NotEqual, &notEqual); masm.j(Assembler::NotEqual, &notEqual);
{ {
masm.cmp32(lhs.payloadReg(), rhs.payloadReg()); masm.cmp32(lhs.payloadReg(), rhs.payloadReg());
emitSet(cond, output); masm.emitSet(cond, output);
masm.jump(&done); masm.jump(&done);
} }
masm.bind(&notEqual); masm.bind(&notEqual);
@ -1363,7 +1356,7 @@ CodeGeneratorARM::visitNotI(LNotI *ins)
{ {
// It is hard to optimize !x, so just do it the basic way for now. // It is hard to optimize !x, so just do it the basic way for now.
masm.ma_cmp(ToRegister(ins->input()), Imm32(0)); masm.ma_cmp(ToRegister(ins->input()), Imm32(0));
emitSet(Assembler::Equal, ToRegister(ins->output())); masm.emitSet(Assembler::Equal, ToRegister(ins->output()));
return true; return true;
} }

Просмотреть файл

@ -57,9 +57,6 @@ class CodeGeneratorARM : public CodeGeneratorShared
void emitRoundDouble(const FloatRegister &src, const Register &dest, Label *fail); void emitRoundDouble(const FloatRegister &src, const Register &dest, Label *fail);
// Emits a conditional set.
void emitSet(Assembler::Condition cond, const Register &dest);
// Emits a branch that directs control flow to the true block if |cond| is // Emits a branch that directs control flow to the true block if |cond| is
// true, and the false block if |cond| is false. // true, and the false block if |cond| is false.
void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse); void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);

Просмотреть файл

@ -1065,6 +1065,13 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
ma_lsl(imm, dest, dest); ma_lsl(imm, dest, dest);
} }
void
emitSet(Assembler::Condition cond, const Register &dest)
{
ma_mov(Imm32(0), dest);
ma_mov(Imm32(1), dest, NoSetCond, cond);
}
// Setup a call to C/C++ code, given the number of general arguments it // Setup a call to C/C++ code, given the number of general arguments it
// takes. Note that this only supports cdecl. // takes. Note that this only supports cdecl.
// //

Просмотреть файл

@ -120,42 +120,6 @@ CodeGeneratorX86Shared::visitTestDAndBranch(LTestDAndBranch *test)
return true; return true;
} }
void
CodeGeneratorX86Shared::emitSet(Assembler::Condition cond, const Register &dest,
Assembler::NaNCond ifNaN)
{
if (GeneralRegisterSet(Registers::SingleByteRegs).has(dest)) {
// If the register we're defining is a single byte register,
// take advantage of the setCC instruction
masm.setCC(cond, dest);
masm.movzxbl(dest, dest);
if (ifNaN != Assembler::NaN_Unexpected) {
Label noNaN;
masm.j(Assembler::NoParity, &noNaN);
if (ifNaN == Assembler::NaN_IsTrue)
masm.movl(Imm32(1), dest);
else
masm.xorl(dest, dest);
masm.bind(&noNaN);
}
} else {
Label end;
Label ifFalse;
if (ifNaN == Assembler::NaN_IsFalse)
masm.j(Assembler::Parity, &ifFalse);
masm.movl(Imm32(1), dest);
masm.j(cond, &end);
if (ifNaN == Assembler::NaN_IsTrue)
masm.j(Assembler::Parity, &end);
masm.bind(&ifFalse);
masm.xorl(dest, dest);
masm.bind(&end);
}
}
void void
CodeGeneratorX86Shared::emitCompare(MCompare::CompareType type, const LAllocation *left, const LAllocation *right) CodeGeneratorX86Shared::emitCompare(MCompare::CompareType type, const LAllocation *left, const LAllocation *right)
{ {
@ -176,7 +140,7 @@ bool
CodeGeneratorX86Shared::visitCompare(LCompare *comp) CodeGeneratorX86Shared::visitCompare(LCompare *comp)
{ {
emitCompare(comp->mir()->compareType(), comp->left(), comp->right()); emitCompare(comp->mir()->compareType(), comp->left(), comp->right());
emitSet(JSOpToCondition(comp->jsop()), ToRegister(comp->output())); masm.emitSet(JSOpToCondition(comp->jsop()), ToRegister(comp->output()));
return true; return true;
} }
@ -197,7 +161,7 @@ CodeGeneratorX86Shared::visitCompareD(LCompareD *comp)
Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop()); Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
masm.compareDouble(cond, lhs, rhs); masm.compareDouble(cond, lhs, rhs);
emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()), masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()),
Assembler::NaNCondFromDoubleCondition(cond)); Assembler::NaNCondFromDoubleCondition(cond));
return true; return true;
} }
@ -206,7 +170,7 @@ bool
CodeGeneratorX86Shared::visitNotI(LNotI *ins) CodeGeneratorX86Shared::visitNotI(LNotI *ins)
{ {
masm.cmpl(ToRegister(ins->input()), Imm32(0)); masm.cmpl(ToRegister(ins->input()), Imm32(0));
emitSet(Assembler::Equal, ToRegister(ins->output())); masm.emitSet(Assembler::Equal, ToRegister(ins->output()));
return true; return true;
} }
@ -217,7 +181,7 @@ CodeGeneratorX86Shared::visitNotD(LNotD *ins)
masm.xorpd(ScratchFloatReg, ScratchFloatReg); masm.xorpd(ScratchFloatReg, ScratchFloatReg);
masm.compareDouble(Assembler::DoubleEqualOrUnordered, opd, ScratchFloatReg); masm.compareDouble(Assembler::DoubleEqualOrUnordered, opd, ScratchFloatReg);
emitSet(Assembler::Equal, ToRegister(ins->output()), Assembler::NaN_IsTrue); masm.emitSet(Assembler::Equal, ToRegister(ins->output()), Assembler::NaN_IsTrue);
return true; return true;
} }

Просмотреть файл

@ -64,11 +64,6 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
void emitCompare(MCompare::CompareType type, const LAllocation *left, const LAllocation *right); void emitCompare(MCompare::CompareType type, const LAllocation *left, const LAllocation *right);
// Emits a conditional set.
void emitSet(Assembler::Condition cond, const Register &dest,
Assembler::NaNCond ifNaN = Assembler::NaN_Unexpected);
void emitSet(Assembler::DoubleCondition cond, const Register &dest);
// Emits a branch that directs control flow to the true block if |cond| is // Emits a branch that directs control flow to the true block if |cond| is
// true, and the false block if |cond| is false. // true, and the false block if |cond| is false.
void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse, void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse,

Просмотреть файл

@ -351,7 +351,7 @@ class MacroAssemblerX86Shared : public Assembler
} }
bool maybeInlineDouble(uint64_t u, const FloatRegister &dest) { bool maybeInlineDouble(uint64_t u, const FloatRegister &dest) {
// This implements parts of "13.4 Generating constants" of // This implements parts of "13.4 Generating constants" of
// "2. Optimizing subroutines in assembly language" by Agner Fog. // "2. Optimizing subroutines in assembly language" by Agner Fog.
switch (u) { switch (u) {
case 0x0000000000000000ULL: // 0.0 case 0x0000000000000000ULL: // 0.0
@ -391,6 +391,40 @@ class MacroAssemblerX86Shared : public Assembler
return true; return true;
} }
void emitSet(Assembler::Condition cond, const Register &dest,
Assembler::NaNCond ifNaN = Assembler::NaN_Unexpected) {
if (GeneralRegisterSet(Registers::SingleByteRegs).has(dest)) {
// If the register we're defining is a single byte register,
// take advantage of the setCC instruction
setCC(cond, dest);
movzxbl(dest, dest);
if (ifNaN != Assembler::NaN_Unexpected) {
Label noNaN;
j(Assembler::NoParity, &noNaN);
if (ifNaN == Assembler::NaN_IsTrue)
movl(Imm32(1), dest);
else
xorl(dest, dest);
bind(&noNaN);
}
} else {
Label end;
Label ifFalse;
if (ifNaN == Assembler::NaN_IsFalse)
j(Assembler::Parity, &ifFalse);
movl(Imm32(1), dest);
j(cond, &end);
if (ifNaN == Assembler::NaN_IsTrue)
j(Assembler::Parity, &end);
bind(&ifFalse);
xorl(dest, dest);
bind(&end);
}
}
// Emit a JMP that can be toggled to a CMP. See ToggleToJmp(), ToggleToCmp(). // Emit a JMP that can be toggled to a CMP. See ToggleToJmp(), ToggleToCmp().
CodeOffsetLabel toggledJump(Label *label) { CodeOffsetLabel toggledJump(Label *label) {
CodeOffsetLabel offset(size()); CodeOffsetLabel offset(size());

Просмотреть файл

@ -347,7 +347,7 @@ CodeGeneratorX64::visitCompareB(LCompareB *lir)
// Perform the comparison. // Perform the comparison.
masm.cmpq(lhs.valueReg(), ScratchReg); masm.cmpq(lhs.valueReg(), ScratchReg);
emitSet(JSOpToCondition(mir->jsop()), output); masm.emitSet(JSOpToCondition(mir->jsop()), output);
return true; return true;
} }
@ -380,11 +380,10 @@ CodeGeneratorX64::visitCompareV(LCompareV *lir)
const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput); const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput);
const Register output = ToRegister(lir->output()); const Register output = ToRegister(lir->output());
JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || JS_ASSERT(IsEqualityOp(mir->jsop()));
mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE);
masm.cmpq(lhs.valueReg(), rhs.valueReg()); masm.cmpq(lhs.valueReg(), rhs.valueReg());
emitSet(JSOpToCondition(mir->jsop()), output); masm.emitSet(JSOpToCondition(mir->jsop()), output);
return true; return true;
} }

Просмотреть файл

@ -351,7 +351,7 @@ CodeGeneratorX86::visitCompareB(LCompareB *lir)
masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean())); masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean()));
else else
masm.cmp32(lhs.payloadReg(), ToRegister(rhs)); masm.cmp32(lhs.payloadReg(), ToRegister(rhs));
emitSet(JSOpToCondition(mir->jsop()), output); masm.emitSet(JSOpToCondition(mir->jsop()), output);
masm.jump(&done); masm.jump(&done);
} }
masm.bind(&notBoolean); masm.bind(&notBoolean);
@ -394,15 +394,14 @@ CodeGeneratorX86::visitCompareV(LCompareV *lir)
const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput); const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput);
const Register output = ToRegister(lir->output()); const Register output = ToRegister(lir->output());
JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || JS_ASSERT(IsEqualityOp(mir->jsop()));
mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE);
Label notEqual, done; Label notEqual, done;
masm.cmp32(lhs.typeReg(), rhs.typeReg()); masm.cmp32(lhs.typeReg(), rhs.typeReg());
masm.j(Assembler::NotEqual, &notEqual); masm.j(Assembler::NotEqual, &notEqual);
{ {
masm.cmp32(lhs.payloadReg(), rhs.payloadReg()); masm.cmp32(lhs.payloadReg(), rhs.payloadReg());
emitSet(cond, output); masm.emitSet(cond, output);
masm.jump(&done); masm.jump(&done);
} }
masm.bind(&notEqual); masm.bind(&notEqual);

Просмотреть файл

@ -459,6 +459,12 @@ IsGlobalOp(JSOp op)
return js_CodeSpec[op].format & JOF_GNAME; return js_CodeSpec[op].format & JOF_GNAME;
} }
inline bool
IsEqualityOp(JSOp op)
{
return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
}
inline bool inline bool
IsGetterPC(jsbytecode *pc) IsGetterPC(jsbytecode *pc)
{ {