Bug 935016 - Specialize string.split(string) in IonMonkey. r=bhackett

This commit is contained in:
Jan de Mooij 2013-11-07 12:14:20 +01:00
parent af9108eea2
commit c5b0c157d3
14 changed files with 171 additions and 1 deletions

View File

@ -7451,6 +7451,18 @@ GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
}
}
if (native == js::str_split && args.length() == 1 && args[0].isString()) {
res.set(NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject));
if (!res)
return false;
types::TypeObject *type = types::TypeScript::InitObject(cx, script, pc, JSProto_Array);
if (!type)
return false;
res->setType(type);
return true;
}
if (native == js_String) {
RootedString emptyString(cx, cx->runtime()->emptyString);
res.set(StringObject::create(cx, emptyString, TenuredObject));

View File

@ -4625,6 +4625,19 @@ CodeGenerator::visitFromCharCode(LFromCharCode *lir)
return true;
}
typedef JSObject *(*StringSplitFn)(JSContext *, HandleTypeObject, HandleString, HandleString);
static const VMFunction StringSplitInfo = FunctionInfo<StringSplitFn>(js::str_split_string);
bool
CodeGenerator::visitStringSplit(LStringSplit *lir)
{
pushArg(ToRegister(lir->separator()));
pushArg(ToRegister(lir->string()));
pushArg(ImmGCPtr(lir->mir()->typeObject()));
return callVM(StringSplitInfo, lir);
}
bool
CodeGenerator::visitInitializedLength(LInitializedLength *lir)
{

View File

@ -201,6 +201,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitConcatPar(LConcatPar *lir);
bool visitCharCodeAt(LCharCodeAt *lir);
bool visitFromCharCode(LFromCharCode *lir);
bool visitStringSplit(LStringSplit *lir);
bool visitFunctionEnvironment(LFunctionEnvironment *lir);
bool visitForkJoinSlice(LForkJoinSlice *lir);
bool visitGuardThreadLocalObject(LGuardThreadLocalObject *lir);

View File

@ -559,6 +559,7 @@ class IonBuilder : public MIRGenerator
// String natives.
InliningStatus inlineStringObject(CallInfo &callInfo);
InliningStatus inlineStringSplit(CallInfo &callInfo);
InliningStatus inlineStrCharCodeAt(CallInfo &callInfo);
InliningStatus inlineStrFromCharCode(CallInfo &callInfo);
InliningStatus inlineStrCharAt(CallInfo &callInfo);

View File

@ -2720,6 +2720,26 @@ class LFromCharCode : public LInstructionHelper<1, 1, 0>
}
};
class LStringSplit : public LCallInstructionHelper<1, 2, 0>
{
public:
LIR_HEADER(StringSplit)
LStringSplit(const LAllocation &string, const LAllocation &separator) {
setOperand(0, string);
setOperand(1, separator);
}
const LAllocation *string() {
return getOperand(0);
}
const LAllocation *separator() {
return getOperand(1);
}
const MStringSplit *mir() const {
return mir_->toStringSplit();
}
};
// Convert a 32-bit integer to a double.
class LInt32ToDouble : public LInstructionHelper<1, 1, 0>
{

View File

@ -126,6 +126,7 @@
_(ConcatPar) \
_(CharCodeAt) \
_(FromCharCode) \
_(StringSplit) \
_(Int32ToDouble) \
_(Float32ToDouble) \
_(DoubleToFloat32) \

View File

@ -2524,6 +2524,18 @@ LIRGenerator::visitArrayConcat(MArrayConcat *ins)
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitStringSplit(MStringSplit *ins)
{
JS_ASSERT(ins->type() == MIRType_Object);
JS_ASSERT(ins->string()->type() == MIRType_String);
JS_ASSERT(ins->separator()->type() == MIRType_String);
LStringSplit *lir = new LStringSplit(useRegisterAtStart(ins->string()),
useRegisterAtStart(ins->separator()));
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitLoadTypedArrayElement(MLoadTypedArrayElement *ins)
{

View File

@ -148,6 +148,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitConcatPar(MConcatPar *ins);
bool visitCharCodeAt(MCharCodeAt *ins);
bool visitFromCharCode(MFromCharCode *ins);
bool visitStringSplit(MStringSplit *ins);
bool visitStart(MStart *start);
bool visitOsrEntry(MOsrEntry *entry);
bool visitNop(MNop *nop);

View File

@ -105,6 +105,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSNative native)
// String natives.
if (native == js_String)
return inlineStringObject(callInfo);
if (native == js::str_split)
return inlineStringSplit(callInfo);
if (native == js_str_charCodeAt)
return inlineStrCharCodeAt(callInfo);
if (native == js::str_fromCharCode)
@ -910,6 +912,43 @@ IonBuilder::inlineStringObject(CallInfo &callInfo)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineStringSplit(CallInfo &callInfo)
{
if (callInfo.argc() != 1 || callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.thisArg()->type() != MIRType_String)
return InliningStatus_NotInlined;
if (callInfo.getArg(0)->type() != MIRType_String)
return InliningStatus_NotInlined;
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js::str_split);
if (!templateObject)
return InliningStatus_NotInlined;
JS_ASSERT(templateObject->is<ArrayObject>());
types::TypeObjectKey *retType = types::TypeObjectKey::get(templateObject);
if (retType->unknownProperties())
return InliningStatus_NotInlined;
types::HeapTypeSetKey key = retType->property(JSID_VOID);
if (!key.maybeTypes())
return InliningStatus_NotInlined;
if (!key.maybeTypes()->hasType(types::Type::StringType())) {
key.freeze(constraints());
return InliningStatus_NotInlined;
}
callInfo.unwrapArgs();
MStringSplit *ins = MStringSplit::New(callInfo.thisArg(), callInfo.getArg(0), templateObject);
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineStrCharCodeAt(CallInfo &callInfo)
{

View File

@ -4152,6 +4152,48 @@ class MFromCharCode
}
};
class MStringSplit
: public MBinaryInstruction,
public MixPolicy<StringPolicy<0>, StringPolicy<1> >
{
types::TypeObject *typeObject_;
MStringSplit(MDefinition *string, MDefinition *sep, JSObject *templateObject)
: MBinaryInstruction(string, sep),
typeObject_(templateObject->type())
{
setResultType(MIRType_Object);
setResultTypeSet(MakeSingletonTypeSet(templateObject));
}
public:
INSTRUCTION_HEADER(StringSplit)
static MStringSplit *New(MDefinition *string, MDefinition *sep, JSObject *templateObject) {
return new MStringSplit(string, sep, templateObject);
}
types::TypeObject *typeObject() const {
return typeObject_;
}
MDefinition *string() const {
return getOperand(0);
}
MDefinition *separator() const {
return getOperand(1);
}
TypePolicy *typePolicy() {
return this;
}
bool possiblyCalls() const {
return true;
}
virtual AliasSet getAliasSet() const {
// Although this instruction returns a new array, we don't have to mark
// it as store instruction, see also MNewArray.
return AliasSet::None();
}
};
// Returns an object to use as |this| value. See also ComputeThis and
// BoxNonStrictThis in Interpreter.h.
class MComputeThis

View File

@ -72,6 +72,7 @@ namespace jit {
_(ConcatPar) \
_(CharCodeAt) \
_(FromCharCode) \
_(StringSplit) \
_(Return) \
_(Throw) \
_(Box) \

View File

@ -163,6 +163,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
SAFE_OP(ConcatPar)
UNSAFE_OP(CharCodeAt)
UNSAFE_OP(FromCharCode)
UNSAFE_OP(StringSplit)
SAFE_OP(Return)
CUSTOM_OP(Throw)
SAFE_OP(Box) // Boxing just creates a JSVal, doesn't alloc.

View File

@ -3005,7 +3005,7 @@ class SplitMatchResult {
} /* anonymous namespace */
template<class Matcher>
static JSObject *
static ArrayObject *
SplitHelper(JSContext *cx, Handle<JSLinearString*> str, uint32_t limit, const Matcher &splitMatch,
Handle<TypeObject*> type)
{
@ -3289,6 +3289,28 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp)
return true;
}
JSObject *
js::str_split_string(JSContext *cx, HandleTypeObject type, HandleString str, HandleString sep)
{
Rooted<JSLinearString*> linearStr(cx, str->ensureLinear(cx));
if (!linearStr)
return nullptr;
Rooted<JSLinearString*> linearSep(cx, sep->ensureLinear(cx));
if (!linearSep)
return nullptr;
uint32_t limit = UINT32_MAX;
SplitStringMatcher matcher(cx, linearSep);
ArrayObject *aobj = SplitHelper(cx, linearStr, limit, matcher, type);
if (!aobj)
return nullptr;
aobj->setType(type);
return aobj;
}
static bool
str_substr(JSContext *cx, unsigned argc, Value *vp)
{

View File

@ -13,6 +13,7 @@
#include "jsutil.h"
#include "NamespaceImports.h"
#include "gc/Rooting.h"
#include "js/RootingAPI.h"
#include "vm/Unicode.h"
@ -355,6 +356,9 @@ str_search(JSContext *cx, unsigned argc, Value *vp);
bool
str_split(JSContext *cx, unsigned argc, Value *vp);
JSObject *
str_split_string(JSContext *cx, HandleTypeObject type, HandleString str, HandleString sep);
bool
str_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
MutableHandleObject objp);