зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1382837 - Optimize Array.join in ion for empty and single-item arrays. r=tcampbell
This commit is contained in:
Родитель
186677c392
Коммит
fb3ee9fa6a
|
@ -9295,10 +9295,45 @@ static const VMFunction ArrayJoinInfo = FunctionInfo<ArrayJoinFn>(jit::ArrayJoin
|
|||
void
|
||||
CodeGenerator::visitArrayJoin(LArrayJoin* lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->separator()));
|
||||
pushArg(ToRegister(lir->array()));
|
||||
Label skipCall;
|
||||
|
||||
Register output = ToRegister(lir->output());
|
||||
Register sep = ToRegister(lir->separator());
|
||||
Register array = ToRegister(lir->array());
|
||||
if (lir->mir()->optimizeForArray()) {
|
||||
Register temp = ToRegister(lir->temp());
|
||||
|
||||
masm.loadPtr(Address(array, NativeObject::offsetOfElements()), temp);
|
||||
Address length(temp, ObjectElements::offsetOfLength());
|
||||
Address initLength(temp, ObjectElements::offsetOfInitializedLength());
|
||||
|
||||
// Check for length == 0
|
||||
Label notEmpty;
|
||||
masm.branch32(Assembler::NotEqual, length, Imm32(0), ¬Empty);
|
||||
const JSAtomState& names = GetJitContext()->runtime->names();
|
||||
masm.movePtr(ImmGCPtr(names.empty), output);
|
||||
masm.jump(&skipCall);
|
||||
|
||||
masm.bind(¬Empty);
|
||||
Label notSingleString;
|
||||
// Check for length == 1, initializedLength >= 1, arr[0].isString()
|
||||
masm.branch32(Assembler::NotEqual, length, Imm32(1), ¬SingleString);
|
||||
masm.branch32(Assembler::LessThan, initLength, Imm32(1), ¬SingleString);
|
||||
|
||||
Address elem0(temp, 0);
|
||||
masm.branchTestString(Assembler::NotEqual, elem0, ¬SingleString);
|
||||
|
||||
// At this point, 'output' can be used as a scratch register, since we're
|
||||
// guaranteed to succeed.
|
||||
masm.unboxString(elem0, output);
|
||||
masm.jump(&skipCall);
|
||||
masm.bind(¬SingleString);
|
||||
}
|
||||
|
||||
pushArg(sep);
|
||||
pushArg(array);
|
||||
callVM(ArrayJoinInfo, lir);
|
||||
masm.bind(&skipCall);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -3542,8 +3542,13 @@ LIRGenerator::visitArrayJoin(MArrayJoin* ins)
|
|||
MOZ_ASSERT(ins->array()->type() == MIRType::Object);
|
||||
MOZ_ASSERT(ins->sep()->type() == MIRType::String);
|
||||
|
||||
LDefinition tempDef = LDefinition::BogusTemp();
|
||||
if (ins->optimizeForArray())
|
||||
tempDef = temp();
|
||||
|
||||
LArrayJoin* lir = new(alloc()) LArrayJoin(useRegisterAtStart(ins->array()),
|
||||
useRegisterAtStart(ins->sep()));
|
||||
useRegisterAtStart(ins->sep()),
|
||||
tempDef);
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
|
|
@ -758,9 +758,25 @@ IonBuilder::inlineArrayJoin(CallInfo& callInfo)
|
|||
if (callInfo.getArg(0)->type() != MIRType::String)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// If we can confirm that the class is an array, the codegen
|
||||
// for MArrayJoin can be notified to check for common empty and one-item arrays.
|
||||
bool optimizeForArray = ([&](){
|
||||
TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet();
|
||||
if (!thisTypes)
|
||||
return false;
|
||||
|
||||
const Class* clasp = thisTypes->getKnownClass(constraints());
|
||||
// TODO: Handle unboxed arrays?
|
||||
if (clasp != &ArrayObject::class_)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
})();
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MArrayJoin* ins = MArrayJoin::New(alloc(), callInfo.thisArg(), callInfo.getArg(0));
|
||||
MArrayJoin* ins = MArrayJoin::New(alloc(), callInfo.thisArg(), callInfo.getArg(0),
|
||||
optimizeForArray);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
|
|
@ -10167,8 +10167,11 @@ class MArrayJoin
|
|||
: public MBinaryInstruction,
|
||||
public MixPolicy<ObjectPolicy<0>, StringPolicy<1> >::Data
|
||||
{
|
||||
MArrayJoin(MDefinition* array, MDefinition* sep)
|
||||
: MBinaryInstruction(array, sep)
|
||||
bool optimizeForArray_;
|
||||
|
||||
MArrayJoin(MDefinition* array, MDefinition* sep, bool optimizeForArray)
|
||||
: MBinaryInstruction(array, sep),
|
||||
optimizeForArray_(optimizeForArray)
|
||||
{
|
||||
setResultType(MIRType::String);
|
||||
}
|
||||
|
@ -10177,6 +10180,9 @@ class MArrayJoin
|
|||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, array), (1, sep))
|
||||
|
||||
bool optimizeForArray() const {
|
||||
return optimizeForArray_;
|
||||
}
|
||||
bool possiblyCalls() const override {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -6179,25 +6179,34 @@ class LArraySlice : public LCallInstructionHelper<1, 3, 2>
|
|||
}
|
||||
};
|
||||
|
||||
class LArrayJoin : public LCallInstructionHelper<1, 2, 0>
|
||||
class LArrayJoin : public LCallInstructionHelper<1, 2, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ArrayJoin)
|
||||
|
||||
LArrayJoin(const LAllocation& array, const LAllocation& sep) {
|
||||
LArrayJoin(const LAllocation& array, const LAllocation& sep,
|
||||
const LDefinition& temp)
|
||||
{
|
||||
setOperand(0, array);
|
||||
setOperand(1, sep);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const MArrayJoin* mir() const {
|
||||
return mir_->toArrayJoin();
|
||||
}
|
||||
const LDefinition* output() {
|
||||
return getDef(0);
|
||||
}
|
||||
const LAllocation* array() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* separator() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
};
|
||||
|
||||
class LLoadUnboxedScalar : public LInstructionHelper<1, 2, 1>
|
||||
|
|
|
@ -789,6 +789,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
|
||||
void unboxString(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
|
||||
void unboxString(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
|
||||
void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); }
|
||||
|
||||
void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
|
||||
void unboxSymbol(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
|
||||
|
|
Загрузка…
Ссылка в новой задаче