Bug 688219 - Cache String.prototype.split. r=djvj

This commit is contained in:
Victor Carlquist 2015-02-11 18:04:54 -05:00
Родитель a370913d32
Коммит d220fbbd3f
5 изменённых файлов: 152 добавлений и 4 удалений

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

@ -476,13 +476,34 @@ BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
if (stub->isCall_Native() && stub->toCall_Native()->callee()->native() == native)
return stub->toCall_Native()->templateObject();
if (stub->isCall_StringSplit() && native == js::str_split)
return stub->toCall_StringSplit()->templateObject();
}
return nullptr;
}
bool
BaselineInspector::isOptimizableCallStringSplit(jsbytecode *pc, JSString **stringOut, JSString **stringArg,
NativeObject **objOut)
{
if (!hasBaselineScript())
return false;
const ICEntry &entry = icEntryFromPC(pc);
// If StringSplit stub is attached, must have only one stub attached.
if (entry.fallbackStub()->numOptimizedStubs() != 1)
return false;
ICStub *stub = entry.firstStub();
if (stub->kind() != ICStub::Call_StringSplit)
return false;
*stringOut = stub->toCall_StringSplit()->expectedThis();
*stringArg = stub->toCall_StringSplit()->expectedArg();
*objOut = stub->toCall_StringSplit()->templateObject();
return true;
}
JSObject *
BaselineInspector::getTemplateObjectForClassHook(jsbytecode *pc, const Class *clasp)
{

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

@ -112,6 +112,8 @@ class BaselineInspector
bool hasSeenDoubleResult(jsbytecode *pc);
bool hasSeenNonStringIterMore(jsbytecode *pc);
bool isOptimizableCallStringSplit(jsbytecode *pc, JSString **stringOut, JSString **stringArg,
NativeObject **objOut);
JSObject *getTemplateObject(jsbytecode *pc);
JSObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
JSObject *getTemplateObjectForClassHook(jsbytecode *pc, const Class *clasp);

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

@ -756,6 +756,7 @@ class IonBuilder
// String natives.
InliningStatus inlineStringObject(CallInfo &callInfo);
InliningStatus inlineConstantStringSplit(CallInfo &callInfo);
InliningStatus inlineStringSplit(CallInfo &callInfo);
InliningStatus inlineStrCharCodeAt(CallInfo &callInfo);
InliningStatus inlineConstantCharCodeAt(CallInfo &callInfo);

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

@ -1366,6 +1366,128 @@ IonBuilder::inlineStringObject(CallInfo &callInfo)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineConstantStringSplit(CallInfo &callInfo)
{
if (!callInfo.thisArg()->isConstant())
return InliningStatus_NotInlined;
if (!callInfo.getArg(0)->isConstant())
return InliningStatus_NotInlined;
const js::Value *argval = callInfo.getArg(0)->toConstant()->vp();
if (!argval->isString())
return InliningStatus_NotInlined;
const js::Value *strval = callInfo.thisArg()->toConstant()->vp();
if (!strval->isString())
return InliningStatus_NotInlined;
MOZ_ASSERT(callInfo.getArg(0)->type() == MIRType_String);
MOZ_ASSERT(callInfo.thisArg()->type() == MIRType_String);
// Check if exist a template object in stub.
JSString *stringThis = nullptr;
JSString *stringArg = nullptr;
NativeObject *templateObject = nullptr;
if (!inspector->isOptimizableCallStringSplit(pc, &stringThis, &stringArg, &templateObject))
return InliningStatus_NotInlined;
MOZ_ASSERT(stringThis);
MOZ_ASSERT(stringArg);
MOZ_ASSERT(templateObject);
MOZ_ASSERT(templateObject->is<ArrayObject>());
if (strval->toString() != stringThis)
return InliningStatus_NotInlined;
if (argval->toString() != stringArg)
return InliningStatus_NotInlined;
// Check if |templateObject| is valid.
TypeSet::ObjectKey *retType = TypeSet::ObjectKey::get(templateObject);
if (retType->unknownProperties())
return InliningStatus_NotInlined;
HeapTypeSetKey key = retType->property(JSID_VOID);
if (!key.maybeTypes())
return InliningStatus_NotInlined;
if (!key.maybeTypes()->hasType(TypeSet::StringType()))
return InliningStatus_NotInlined;
uint32_t initLength = templateObject->as<ArrayObject>().length();
if (templateObject->getDenseInitializedLength() != initLength)
return InliningStatus_NotInlined;
Vector<MConstant *, 0, SystemAllocPolicy> arrayValues;
for (uint32_t i = 0; i < initLength; i++) {
MConstant *value = MConstant::New(alloc(), templateObject->getDenseElement(i), constraints());
if (!TypeSetIncludes(key.maybeTypes(), value->type(), value->resultTypeSet()))
return InliningStatus_NotInlined;
if (!arrayValues.append(value))
return InliningStatus_Error;
}
callInfo.setImplicitlyUsedUnchecked();
TemporaryTypeSet::DoubleConversion conversion =
getInlineReturnTypeSet()->convertDoubleElements(constraints());
if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles)
return InliningStatus_NotInlined;
MConstant *templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
current->add(templateConst);
MNewArray *ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
templateObject->group()->initialHeap(constraints()),
NewArray_FullyAllocating);
current->add(ins);
current->push(ins);
if (!initLength) {
if (!resumeAfter(ins))
return InliningStatus_Error;
return InliningStatus_Inlined;
}
// Get the elements vector.
MElements *elements = MElements::New(alloc(), ins);
current->add(elements);
// Store all values, no need to initialize the length after each as
// jsop_initelem_array is doing because we do not expect to bailout
// because the memory is supposed to be allocated by now.
MConstant *id = nullptr;
for (uint32_t i = 0; i < initLength; i++) {
id = MConstant::New(alloc(), Int32Value(i));
current->add(id);
MConstant *value = arrayValues[i];
current->add(value);
MStoreElement *store = MStoreElement::New(alloc(), elements, id, value,
/* needsHoleCheck = */ false);
current->add(store);
// There is normally no need for a post barrier on these writes
// because the new array will be in the nursery. However, this
// assumption is volated if we specifically requested pre-tenuring.
if (ins->initialHeap() == gc::TenuredHeap)
current->add(MPostWriteBarrier::New(alloc(), ins, value));
}
// Update the length.
MSetInitializedLength *length = MSetInitializedLength::New(alloc(), elements, id);
current->add(length);
if (!resumeAfter(length))
return InliningStatus_Error;
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineStringSplit(CallInfo &callInfo)
{
@ -1379,6 +1501,10 @@ IonBuilder::inlineStringSplit(CallInfo &callInfo)
if (callInfo.getArg(0)->type() != MIRType_String)
return InliningStatus_NotInlined;
IonBuilder::InliningStatus resultConstStringSplit = inlineConstantStringSplit(callInfo);
if (resultConstStringSplit != InliningStatus_NotInlined)
return resultConstStringSplit;
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js::str_split);
if (!templateObject)
return InliningStatus_NotInlined;

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

@ -1213,8 +1213,6 @@ MacroAssembler::initGCThing(Register obj, Register slots, JSObject *templateObj,
Address(obj, NativeObject::offsetOfElements()));
} else if (ntemplate->is<ArrayObject>()) {
Register temp = slots;
MOZ_ASSERT(!ntemplate->getDenseInitializedLength());
int elementsOffset = NativeObject::offsetOfFixedElements();
computeEffectiveAddress(Address(obj, elementsOffset), temp);