Skip to content

Commit 7cb4f81

Browse files
committed
Bug 935016 - Specialize string.split(string) in IonMonkey. r=bhackett
1 parent 9f29749 commit 7cb4f81

14 files changed

+171
-1
lines changed

js/src/jit/BaselineIC.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7451,6 +7451,18 @@ GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
74517451
}
74527452
}
74537453

7454+
if (native == js::str_split && args.length() == 1 && args[0].isString()) {
7455+
res.set(NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject));
7456+
if (!res)
7457+
return false;
7458+
7459+
types::TypeObject *type = types::TypeScript::InitObject(cx, script, pc, JSProto_Array);
7460+
if (!type)
7461+
return false;
7462+
res->setType(type);
7463+
return true;
7464+
}
7465+
74547466
if (native == js_String) {
74557467
RootedString emptyString(cx, cx->runtime()->emptyString);
74567468
res.set(StringObject::create(cx, emptyString, TenuredObject));

js/src/jit/CodeGenerator.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4625,6 +4625,19 @@ CodeGenerator::visitFromCharCode(LFromCharCode *lir)
46254625
return true;
46264626
}
46274627

4628+
typedef JSObject *(*StringSplitFn)(JSContext *, HandleTypeObject, HandleString, HandleString);
4629+
static const VMFunction StringSplitInfo = FunctionInfo<StringSplitFn>(js::str_split_string);
4630+
4631+
bool
4632+
CodeGenerator::visitStringSplit(LStringSplit *lir)
4633+
{
4634+
pushArg(ToRegister(lir->separator()));
4635+
pushArg(ToRegister(lir->string()));
4636+
pushArg(ImmGCPtr(lir->mir()->typeObject()));
4637+
4638+
return callVM(StringSplitInfo, lir);
4639+
}
4640+
46284641
bool
46294642
CodeGenerator::visitInitializedLength(LInitializedLength *lir)
46304643
{

js/src/jit/CodeGenerator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ class CodeGenerator : public CodeGeneratorSpecific
201201
bool visitConcatPar(LConcatPar *lir);
202202
bool visitCharCodeAt(LCharCodeAt *lir);
203203
bool visitFromCharCode(LFromCharCode *lir);
204+
bool visitStringSplit(LStringSplit *lir);
204205
bool visitFunctionEnvironment(LFunctionEnvironment *lir);
205206
bool visitForkJoinSlice(LForkJoinSlice *lir);
206207
bool visitGuardThreadLocalObject(LGuardThreadLocalObject *lir);

js/src/jit/IonBuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ class IonBuilder : public MIRGenerator
559559

560560
// String natives.
561561
InliningStatus inlineStringObject(CallInfo &callInfo);
562+
InliningStatus inlineStringSplit(CallInfo &callInfo);
562563
InliningStatus inlineStrCharCodeAt(CallInfo &callInfo);
563564
InliningStatus inlineStrFromCharCode(CallInfo &callInfo);
564565
InliningStatus inlineStrCharAt(CallInfo &callInfo);

js/src/jit/LIR-Common.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2720,6 +2720,26 @@ class LFromCharCode : public LInstructionHelper<1, 1, 0>
27202720
}
27212721
};
27222722

2723+
class LStringSplit : public LCallInstructionHelper<1, 2, 0>
2724+
{
2725+
public:
2726+
LIR_HEADER(StringSplit)
2727+
2728+
LStringSplit(const LAllocation &string, const LAllocation &separator) {
2729+
setOperand(0, string);
2730+
setOperand(1, separator);
2731+
}
2732+
const LAllocation *string() {
2733+
return getOperand(0);
2734+
}
2735+
const LAllocation *separator() {
2736+
return getOperand(1);
2737+
}
2738+
const MStringSplit *mir() const {
2739+
return mir_->toStringSplit();
2740+
}
2741+
};
2742+
27232743
// Convert a 32-bit integer to a double.
27242744
class LInt32ToDouble : public LInstructionHelper<1, 1, 0>
27252745
{

js/src/jit/LOpcodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
_(ConcatPar) \
127127
_(CharCodeAt) \
128128
_(FromCharCode) \
129+
_(StringSplit) \
129130
_(Int32ToDouble) \
130131
_(Float32ToDouble) \
131132
_(DoubleToFloat32) \

js/src/jit/Lowering.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,6 +2524,18 @@ LIRGenerator::visitArrayConcat(MArrayConcat *ins)
25242524
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
25252525
}
25262526

2527+
bool
2528+
LIRGenerator::visitStringSplit(MStringSplit *ins)
2529+
{
2530+
JS_ASSERT(ins->type() == MIRType_Object);
2531+
JS_ASSERT(ins->string()->type() == MIRType_String);
2532+
JS_ASSERT(ins->separator()->type() == MIRType_String);
2533+
2534+
LStringSplit *lir = new LStringSplit(useRegisterAtStart(ins->string()),
2535+
useRegisterAtStart(ins->separator()));
2536+
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
2537+
}
2538+
25272539
bool
25282540
LIRGenerator::visitLoadTypedArrayElement(MLoadTypedArrayElement *ins)
25292541
{

js/src/jit/Lowering.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ class LIRGenerator : public LIRGeneratorSpecific
148148
bool visitConcatPar(MConcatPar *ins);
149149
bool visitCharCodeAt(MCharCodeAt *ins);
150150
bool visitFromCharCode(MFromCharCode *ins);
151+
bool visitStringSplit(MStringSplit *ins);
151152
bool visitStart(MStart *start);
152153
bool visitOsrEntry(MOsrEntry *entry);
153154
bool visitNop(MNop *nop);

js/src/jit/MCallOptimize.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
105105
// String natives.
106106
if (native == js_String)
107107
return inlineStringObject(callInfo);
108+
if (native == js::str_split)
109+
return inlineStringSplit(callInfo);
108110
if (native == js_str_charCodeAt)
109111
return inlineStrCharCodeAt(callInfo);
110112
if (native == js::str_fromCharCode)
@@ -910,6 +912,43 @@ IonBuilder::inlineStringObject(CallInfo &callInfo)
910912
return InliningStatus_Inlined;
911913
}
912914

915+
IonBuilder::InliningStatus
916+
IonBuilder::inlineStringSplit(CallInfo &callInfo)
917+
{
918+
if (callInfo.argc() != 1 || callInfo.constructing())
919+
return InliningStatus_NotInlined;
920+
if (callInfo.thisArg()->type() != MIRType_String)
921+
return InliningStatus_NotInlined;
922+
if (callInfo.getArg(0)->type() != MIRType_String)
923+
return InliningStatus_NotInlined;
924+
925+
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js::str_split);
926+
if (!templateObject)
927+
return InliningStatus_NotInlined;
928+
JS_ASSERT(templateObject->is<ArrayObject>());
929+
930+
types::TypeObjectKey *retType = types::TypeObjectKey::get(templateObject);
931+
if (retType->unknownProperties())
932+
return InliningStatus_NotInlined;
933+
934+
types::HeapTypeSetKey key = retType->property(JSID_VOID);
935+
if (!key.maybeTypes())
936+
return InliningStatus_NotInlined;
937+
938+
if (!key.maybeTypes()->hasType(types::Type::StringType())) {
939+
key.freeze(constraints());
940+
return InliningStatus_NotInlined;
941+
}
942+
943+
callInfo.unwrapArgs();
944+
945+
MStringSplit *ins = MStringSplit::New(callInfo.thisArg(), callInfo.getArg(0), templateObject);
946+
current->add(ins);
947+
current->push(ins);
948+
949+
return InliningStatus_Inlined;
950+
}
951+
913952
IonBuilder::InliningStatus
914953
IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo)
915954
{

js/src/jit/MIR.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4152,6 +4152,48 @@ class MFromCharCode
41524152
}
41534153
};
41544154

4155+
class MStringSplit
4156+
: public MBinaryInstruction,
4157+
public MixPolicy<StringPolicy<0>, StringPolicy<1> >
4158+
{
4159+
types::TypeObject *typeObject_;
4160+
4161+
MStringSplit(MDefinition *string, MDefinition *sep, JSObject *templateObject)
4162+
: MBinaryInstruction(string, sep),
4163+
typeObject_(templateObject->type())
4164+
{
4165+
setResultType(MIRType_Object);
4166+
setResultTypeSet(MakeSingletonTypeSet(templateObject));
4167+
}
4168+
4169+
public:
4170+
INSTRUCTION_HEADER(StringSplit)
4171+
4172+
static MStringSplit *New(MDefinition *string, MDefinition *sep, JSObject *templateObject) {
4173+
return new MStringSplit(string, sep, templateObject);
4174+
}
4175+
types::TypeObject *typeObject() const {
4176+
return typeObject_;
4177+
}
4178+
MDefinition *string() const {
4179+
return getOperand(0);
4180+
}
4181+
MDefinition *separator() const {
4182+
return getOperand(1);
4183+
}
4184+
TypePolicy *typePolicy() {
4185+
return this;
4186+
}
4187+
bool possiblyCalls() const {
4188+
return true;
4189+
}
4190+
virtual AliasSet getAliasSet() const {
4191+
// Although this instruction returns a new array, we don't have to mark
4192+
// it as store instruction, see also MNewArray.
4193+
return AliasSet::None();
4194+
}
4195+
};
4196+
41554197
// Returns an object to use as |this| value. See also ComputeThis and
41564198
// BoxNonStrictThis in Interpreter.h.
41574199
class MComputeThis

0 commit comments

Comments
 (0)