mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 03:35:33 +00:00
Bug 887016 - Part 7: Add RegExpInstanceOptimizable. r=nbp
This commit is contained in:
parent
e866ceb7f2
commit
1b4d64f711
@ -1104,3 +1104,55 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto, uint8_t* resul
|
||||
*result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::RegExpInstanceOptimizable(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
// This can only be called from self-hosted code.
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
|
||||
uint8_t result = false;
|
||||
if (!RegExpInstanceOptimizableRaw(cx, &args[0].toObject(), &args[1].toObject(), &result))
|
||||
return false;
|
||||
|
||||
args.rval().setBoolean(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::RegExpInstanceOptimizableRaw(JSContext* cx, JSObject* rx, JSObject* proto, uint8_t* result)
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (!rx->isNative()) {
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
NativeObject* nobj = static_cast<NativeObject*>(rx);
|
||||
|
||||
Shape* shape = cx->compartment()->regExps.getOptimizableRegExpInstanceShape();
|
||||
if (shape == nobj->lastProperty()) {
|
||||
*result = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rx->hasLazyPrototype()) {
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rx->getTaggedProto().toObjectOrNull() != proto) {
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!RegExpObject::isInitialShape(nobj)) {
|
||||
*result = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
cx->compartment()->regExps.setOptimizableRegExpInstanceShape(nobj->lastProperty());
|
||||
*result = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -97,6 +97,12 @@ RegExpPrototypeOptimizable(JSContext* cx, unsigned argc, Value* vp);
|
||||
extern bool
|
||||
RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto, uint8_t* result);
|
||||
|
||||
extern bool
|
||||
RegExpInstanceOptimizable(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
extern bool
|
||||
RegExpInstanceOptimizableRaw(JSContext* cx, JSObject* rx, JSObject* proto, uint8_t* result);
|
||||
|
||||
// RegExp ClassSpec members used in RegExpObject.cpp.
|
||||
extern bool
|
||||
regexp_construct(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
@ -2035,6 +2035,77 @@ CodeGenerator::visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototype
|
||||
masm.jump(ool->rejoin());
|
||||
}
|
||||
|
||||
class OutOfLineRegExpInstanceOptimizable : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
LRegExpInstanceOptimizable* ins_;
|
||||
|
||||
public:
|
||||
explicit OutOfLineRegExpInstanceOptimizable(LRegExpInstanceOptimizable* ins)
|
||||
: ins_(ins)
|
||||
{ }
|
||||
|
||||
void accept(CodeGenerator* codegen) {
|
||||
codegen->visitOutOfLineRegExpInstanceOptimizable(this);
|
||||
}
|
||||
LRegExpInstanceOptimizable* ins() const {
|
||||
return ins_;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
CodeGenerator::visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* ins)
|
||||
{
|
||||
Register object = ToRegister(ins->object());
|
||||
Register output = ToRegister(ins->output());
|
||||
Register temp = ToRegister(ins->temp());
|
||||
|
||||
OutOfLineRegExpInstanceOptimizable* ool = new(alloc()) OutOfLineRegExpInstanceOptimizable(ins);
|
||||
addOutOfLineCode(ool, ins->mir());
|
||||
|
||||
masm.loadJSContext(temp);
|
||||
masm.loadPtr(Address(temp, JSContext::offsetOfCompartment()), temp);
|
||||
masm.loadPtr(Address(temp, JSCompartment::offsetOfRegExps()), temp);
|
||||
masm.loadPtr(Address(temp, RegExpCompartment::offsetOfOptimizableRegExpInstanceShape()),
|
||||
temp);
|
||||
|
||||
masm.loadPtr(Address(object, JSObject::offsetOfShape()), output);
|
||||
masm.branchPtr(Assembler::NotEqual, output, temp, ool->entry());
|
||||
masm.move32(Imm32(0x1), output);
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOptimizable* ool)
|
||||
{
|
||||
LRegExpInstanceOptimizable* ins = ool->ins();
|
||||
Register object = ToRegister(ins->object());
|
||||
Register proto = ToRegister(ins->proto());
|
||||
Register output = ToRegister(ins->output());
|
||||
Register temp = ToRegister(ins->temp());
|
||||
|
||||
saveVolatile(output);
|
||||
|
||||
masm.reserveStack(sizeof(void*));
|
||||
masm.moveStackPtrTo(temp);
|
||||
|
||||
masm.setupUnalignedABICall(output);
|
||||
masm.loadJSContext(output);
|
||||
masm.passABIArg(output);
|
||||
masm.passABIArg(object);
|
||||
masm.passABIArg(proto);
|
||||
masm.passABIArg(temp);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, RegExpInstanceOptimizableRaw));
|
||||
masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
|
||||
|
||||
masm.load8ZeroExtend(Address(masm.getStackPointer(), 0), output);
|
||||
masm.freeStack(sizeof(void*));
|
||||
|
||||
restoreVolatile(output);
|
||||
|
||||
masm.jump(ool->rejoin());
|
||||
}
|
||||
|
||||
typedef JSString* (*RegExpReplaceFn)(JSContext*, HandleString, HandleObject, HandleString);
|
||||
static const VMFunction RegExpReplaceInfo = FunctionInfo<RegExpReplaceFn>(RegExpReplace);
|
||||
|
||||
|
@ -49,6 +49,7 @@ class OutOfLineIsConstructor;
|
||||
class OutOfLineRegExpMatcher;
|
||||
class OutOfLineRegExpTester;
|
||||
class OutOfLineRegExpPrototypeOptimizable;
|
||||
class OutOfLineRegExpInstanceOptimizable;
|
||||
class OutOfLineLambdaArrow;
|
||||
|
||||
class CodeGenerator : public CodeGeneratorSpecific
|
||||
@ -116,6 +117,8 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void visitOutOfLineRegExpTester(OutOfLineRegExpTester* ool);
|
||||
void visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* lir);
|
||||
void visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool);
|
||||
void visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* lir);
|
||||
void visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOptimizable* ool);
|
||||
void visitRegExpReplace(LRegExpReplace* lir);
|
||||
void visitStringReplace(LStringReplace* lir);
|
||||
void emitSharedStub(ICStub::Kind kind, LInstruction* lir);
|
||||
|
@ -69,6 +69,7 @@
|
||||
_(RegExpTester) \
|
||||
_(IsRegExpObject) \
|
||||
_(RegExpPrototypeOptimizable) \
|
||||
_(RegExpInstanceOptimizable) \
|
||||
\
|
||||
_(String) \
|
||||
_(StringSplit) \
|
||||
|
@ -824,6 +824,7 @@ class IonBuilder
|
||||
InliningStatus inlineRegExpTester(CallInfo& callInfo);
|
||||
InliningStatus inlineIsRegExpObject(CallInfo& callInfo);
|
||||
InliningStatus inlineRegExpPrototypeOptimizable(CallInfo& callInfo);
|
||||
InliningStatus inlineRegExpInstanceOptimizable(CallInfo& callInfo);
|
||||
|
||||
// Object natives and intrinsics.
|
||||
InliningStatus inlineObjectCreate(CallInfo& callInfo);
|
||||
|
@ -2295,6 +2295,18 @@ LIRGenerator::visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins)
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->object()->type() == MIRType_Object);
|
||||
MOZ_ASSERT(ins->proto()->type() == MIRType_Object);
|
||||
MOZ_ASSERT(ins->type() == MIRType_Boolean);
|
||||
LRegExpInstanceOptimizable* lir = new(alloc()) LRegExpInstanceOptimizable(useRegister(ins->object()),
|
||||
useRegister(ins->proto()),
|
||||
temp());
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitRegExpReplace(MRegExpReplace* ins)
|
||||
{
|
||||
|
@ -166,6 +166,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitRegExpMatcher(MRegExpMatcher* ins);
|
||||
void visitRegExpTester(MRegExpTester* ins);
|
||||
void visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins);
|
||||
void visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins);
|
||||
void visitRegExpReplace(MRegExpReplace* ins);
|
||||
void visitStringReplace(MStringReplace* ins);
|
||||
void visitBinarySharedStub(MBinarySharedStub* ins);
|
||||
|
@ -184,6 +184,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
|
||||
return inlineIsRegExpObject(callInfo);
|
||||
case InlinableNative::RegExpPrototypeOptimizable:
|
||||
return inlineRegExpPrototypeOptimizable(callInfo);
|
||||
case InlinableNative::RegExpInstanceOptimizable:
|
||||
return inlineRegExpInstanceOptimizable(callInfo);
|
||||
|
||||
// String natives.
|
||||
case InlinableNative::String:
|
||||
@ -1909,6 +1911,35 @@ IonBuilder::inlineRegExpPrototypeOptimizable(CallInfo& callInfo)
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineRegExpInstanceOptimizable(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MDefinition* rxArg = callInfo.getArg(0);
|
||||
MDefinition* protoArg = callInfo.getArg(1);
|
||||
|
||||
if (rxArg->type() != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (protoArg->type() != MIRType_Object)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
if (getInlineReturnType() != MIRType_Boolean)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MInstruction* opt = MRegExpInstanceOptimizable::New(alloc(), rxArg, protoArg);
|
||||
current->add(opt);
|
||||
current->push(opt);
|
||||
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineStrReplace(CallInfo& callInfo)
|
||||
{
|
||||
|
@ -8017,6 +8017,35 @@ class MRegExpPrototypeOptimizable
|
||||
}
|
||||
};
|
||||
|
||||
class MRegExpInstanceOptimizable
|
||||
: public MBinaryInstruction,
|
||||
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
|
||||
{
|
||||
explicit MRegExpInstanceOptimizable(MDefinition* object, MDefinition* proto)
|
||||
: MBinaryInstruction(object, proto)
|
||||
{
|
||||
setResultType(MIRType_Boolean);
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(RegExpInstanceOptimizable)
|
||||
|
||||
static MRegExpInstanceOptimizable* New(TempAllocator& alloc, MDefinition* obj,
|
||||
MDefinition* proto) {
|
||||
return new(alloc) MRegExpInstanceOptimizable(obj, proto);
|
||||
}
|
||||
MDefinition* object() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
MDefinition* proto() const {
|
||||
return getOperand(1);
|
||||
}
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Policy1>
|
||||
class MStrReplace
|
||||
: public MTernaryInstruction,
|
||||
|
@ -148,6 +148,7 @@ namespace jit {
|
||||
_(RegExpMatcher) \
|
||||
_(RegExpTester) \
|
||||
_(RegExpPrototypeOptimizable) \
|
||||
_(RegExpInstanceOptimizable) \
|
||||
_(RegExpReplace) \
|
||||
_(StringReplace) \
|
||||
_(Lambda) \
|
||||
|
@ -4353,6 +4353,31 @@ class LRegExpPrototypeOptimizable : public LInstructionHelper<1, 1, 1>
|
||||
}
|
||||
};
|
||||
|
||||
class LRegExpInstanceOptimizable : public LInstructionHelper<1, 2, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(RegExpInstanceOptimizable);
|
||||
explicit LRegExpInstanceOptimizable(const LAllocation& object, const LAllocation& proto,
|
||||
const LDefinition& temp) {
|
||||
setOperand(0, object);
|
||||
setOperand(1, proto);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const LAllocation* object() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* proto() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
MRegExpInstanceOptimizable* mir() const {
|
||||
return mir_->toRegExpInstanceOptimizable();
|
||||
}
|
||||
};
|
||||
|
||||
class LStrReplace : public LCallInstructionHelper<1, 3, 0>
|
||||
{
|
||||
public:
|
||||
|
@ -209,6 +209,7 @@
|
||||
_(RegExpMatcher) \
|
||||
_(RegExpTester) \
|
||||
_(RegExpPrototypeOptimizable) \
|
||||
_(RegExpInstanceOptimizable) \
|
||||
_(RegExpReplace) \
|
||||
_(StringReplace) \
|
||||
_(Substr) \
|
||||
|
@ -721,7 +721,8 @@ RegExpShared::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
RegExpCompartment::RegExpCompartment(JSRuntime* rt)
|
||||
: set_(rt),
|
||||
matchResultTemplateObject_(nullptr),
|
||||
optimizableRegExpPrototypeShape_(nullptr)
|
||||
optimizableRegExpPrototypeShape_(nullptr),
|
||||
optimizableRegExpInstanceShape_(nullptr)
|
||||
{}
|
||||
|
||||
RegExpCompartment::~RegExpCompartment()
|
||||
@ -852,6 +853,12 @@ RegExpCompartment::sweep(JSRuntime* rt)
|
||||
{
|
||||
optimizableRegExpPrototypeShape_.set(nullptr);
|
||||
}
|
||||
|
||||
if (optimizableRegExpInstanceShape_ &&
|
||||
IsAboutToBeFinalized(&optimizableRegExpInstanceShape_))
|
||||
{
|
||||
optimizableRegExpInstanceShape_.set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -336,6 +336,13 @@ class RegExpCompartment
|
||||
*/
|
||||
ReadBarriered<Shape*> optimizableRegExpPrototypeShape_;
|
||||
|
||||
/*
|
||||
* The shape of RegExp instance that satisfies following:
|
||||
* * lastProperty is lastIndex
|
||||
* * prototype is RegExp.prototype
|
||||
*/
|
||||
ReadBarriered<Shape*> optimizableRegExpInstanceShape_;
|
||||
|
||||
ArrayObject* createMatchResultTemplateObject(JSContext* cx);
|
||||
|
||||
public:
|
||||
@ -365,10 +372,19 @@ class RegExpCompartment
|
||||
void setOptimizableRegExpPrototypeShape(Shape* shape) {
|
||||
optimizableRegExpPrototypeShape_ = shape;
|
||||
}
|
||||
Shape* getOptimizableRegExpInstanceShape() {
|
||||
return optimizableRegExpInstanceShape_;
|
||||
}
|
||||
void setOptimizableRegExpInstanceShape(Shape* shape) {
|
||||
optimizableRegExpInstanceShape_ = shape;
|
||||
}
|
||||
|
||||
static size_t offsetOfOptimizableRegExpPrototypeShape() {
|
||||
return offsetof(RegExpCompartment, optimizableRegExpPrototypeShape_);
|
||||
}
|
||||
static size_t offsetOfOptimizableRegExpInstanceShape() {
|
||||
return offsetof(RegExpCompartment, optimizableRegExpInstanceShape_);
|
||||
}
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
};
|
||||
@ -409,6 +425,15 @@ class RegExpObject : public NativeObject
|
||||
|
||||
static unsigned lastIndexSlot() { return LAST_INDEX_SLOT; }
|
||||
|
||||
static bool isInitialShape(NativeObject* nobj) {
|
||||
Shape* shape = nobj->lastProperty();
|
||||
if (!shape->hasSlot())
|
||||
return false;
|
||||
if (shape->maybeSlot() != LAST_INDEX_SLOT)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const Value& getLastIndex() const { return getSlot(LAST_INDEX_SLOT); }
|
||||
|
||||
void setLastIndex(double d) {
|
||||
|
@ -2373,6 +2373,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_FN("RegExpCreate", intrinsic_RegExpCreate, 2,0),
|
||||
JS_INLINABLE_FN("RegExpPrototypeOptimizable", RegExpPrototypeOptimizable, 1,0,
|
||||
RegExpPrototypeOptimizable),
|
||||
JS_INLINABLE_FN("RegExpInstanceOptimizable", RegExpInstanceOptimizable, 1,0,
|
||||
RegExpInstanceOptimizable),
|
||||
|
||||
// See builtin/RegExp.h for descriptions of the regexp_* functions.
|
||||
JS_FN("regexp_exec_no_statics", regexp_exec_no_statics, 2,0),
|
||||
|
Loading…
Reference in New Issue
Block a user