Bug 1030985 - Optimize arguments.callee. (r=h4writer)

This commit is contained in:
Shu-yu Guo 2014-07-07 13:11:11 -07:00
parent 481f2ae7f8
commit 2457dac324
6 changed files with 188 additions and 33 deletions

View File

@ -6071,6 +6071,36 @@ ICGetIntrinsic_Constant::Compiler::generateStubCode(MacroAssembler &masm)
// GetProp_Fallback
//
static bool
TryAttachMagicArgumentsGetPropStub(JSContext *cx, JSScript *script, ICGetProp_Fallback *stub,
HandlePropertyName name, HandleValue val, HandleValue res,
bool *attached)
{
MOZ_ASSERT(!*attached);
if (!val.isMagic(JS_OPTIMIZED_ARGUMENTS))
return true;
// Try handling arguments.callee on optimized arguments.
if (name == cx->names().callee) {
IonSpew(IonSpew_BaselineIC, " Generating GetProp(MagicArgs.callee) stub");
// Unlike ICGetProp_ArgumentsLength, only magic argument stubs are
// supported at the moment.
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
ICGetProp_ArgumentsCallee::Compiler compiler(cx, monitorStub);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
*attached = true;
stub->addNewStub(newStub);
return true;
}
return true;
}
static bool
TryAttachLengthStub(JSContext *cx, JSScript *script, ICGetProp_Fallback *stub, HandleValue val,
HandleValue res, bool *attached)
@ -6426,39 +6456,23 @@ TryAttachNativeDoesNotExistStub(JSContext *cx, HandleScript script, jsbytecode *
}
static bool
DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_,
MutableHandleValue val, MutableHandleValue res)
ComputeGetPropResult(JSContext *cx, BaselineFrame *frame, JSOp op, HandlePropertyName name,
MutableHandleValue val, MutableHandleValue res)
{
// This fallback stub may trigger debug mode toggling.
DebugModeOSRVolatileStub<ICGetProp_Fallback *> stub(frame, stub_);
jsbytecode *pc = stub->icEntry()->pc(frame->script());
JSOp op = JSOp(*pc);
FallbackICSpew(cx, stub, "GetProp(%s)", js_CodeName[op]);
JS_ASSERT(op == JSOP_GETPROP || op == JSOP_CALLPROP || op == JSOP_LENGTH || op == JSOP_GETXPROP);
RootedPropertyName name(cx, frame->script()->getName(pc));
if (op == JSOP_LENGTH && val.isMagic(JS_OPTIMIZED_ARGUMENTS)) {
// Handle arguments.length access.
if (IsOptimizedArguments(frame, val.address())) {
// Handle arguments.length and arguments.callee on optimized arguments, as
// it is not an object.
if (val.isMagic(JS_OPTIMIZED_ARGUMENTS) && IsOptimizedArguments(frame, val.address())) {
if (op == JSOP_LENGTH) {
res.setInt32(frame->numActualArgs());
// Monitor result
types::TypeScript::Monitor(cx, frame->script(), pc, res);
if (!stub->addMonitorStubForValue(cx, frame->script(), res))
return false;
bool attached = false;
if (!TryAttachLengthStub(cx, frame->script(), stub, val, res, &attached))
return false;
JS_ASSERT(attached);
return true;
} else {
MOZ_ASSERT(name == cx->names().callee);
res.setObject(*frame->callee());
}
return true;
}
// Handle when val is an object.
RootedObject obj(cx, ToObjectFromStack(cx, val));
if (!obj)
return false;
@ -6475,6 +6489,26 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_
}
#endif
return true;
}
static bool
DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_,
MutableHandleValue val, MutableHandleValue res)
{
// This fallback stub may trigger debug mode toggling.
DebugModeOSRVolatileStub<ICGetProp_Fallback *> stub(frame, stub_);
jsbytecode *pc = stub->icEntry()->pc(frame->script());
JSOp op = JSOp(*pc);
FallbackICSpew(cx, stub, "GetProp(%s)", js_CodeName[op]);
JS_ASSERT(op == JSOP_GETPROP || op == JSOP_CALLPROP || op == JSOP_LENGTH || op == JSOP_GETXPROP);
RootedPropertyName name(cx, frame->script()->getName(pc));
if (!ComputeGetPropResult(cx, frame, op, name, val, res))
return false;
types::TypeScript::Monitor(cx, frame->script(), pc, res);
// Check if debug mode toggling made the stub invalid.
@ -6499,6 +6533,11 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_
return true;
}
if (!TryAttachMagicArgumentsGetPropStub(cx, frame->script(), stub, name, val, res, &attached))
return false;
if (attached)
return true;
RootedScript script(cx, frame->script());
if (!TryAttachNativeGetPropStub(cx, script, pc, stub, name, val, res, &attached))
@ -7314,6 +7353,31 @@ ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler &masm)
return true;
}
bool
ICGetProp_ArgumentsCallee::Compiler::generateStubCode(MacroAssembler &masm)
{
Label failure;
// Ensure that this is lazy arguments.
masm.branchTestMagicValue(Assembler::NotEqual, R0, JS_OPTIMIZED_ARGUMENTS, &failure);
// Ensure that frame has not loaded different arguments object since.
masm.branchTest32(Assembler::NonZero,
Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFlags()),
Imm32(BaselineFrame::HAS_ARGS_OBJ),
&failure);
Address callee(BaselineFrameReg, BaselineFrame::offsetOfCalleeToken());
masm.loadPtr(callee, R0.scratchReg());
masm.tagValue(JSVAL_TYPE_OBJECT, R0.scratchReg(), R0);
EmitEnterTypeMonitorIC(masm);
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
void
BaselineScript::noteAccessedGetter(uint32_t pcOffset)
{

View File

@ -423,6 +423,7 @@ class ICEntry
_(GetProp_CallDOMProxyWithGenerationNative)\
_(GetProp_DOMProxyShadowed) \
_(GetProp_ArgumentsLength) \
_(GetProp_ArgumentsCallee) \
\
_(SetProp_Fallback) \
_(SetProp_Native) \
@ -5077,6 +5078,41 @@ class ICGetProp_ArgumentsLength : public ICStub
};
};
class ICGetProp_ArgumentsCallee : public ICMonitoredStub
{
friend class ICStubSpace;
protected:
explicit ICGetProp_ArgumentsCallee(JitCode *stubCode, ICStub *firstMonitorStub)
: ICMonitoredStub(ICStub::GetProp_ArgumentsCallee, stubCode, firstMonitorStub)
{ }
public:
static inline ICGetProp_ArgumentsCallee *New(ICStubSpace *space, JitCode *code,
ICStub *firstMonitorStub)
{
if (!code)
return nullptr;
return space->allocate<ICGetProp_ArgumentsCallee>(code, firstMonitorStub);
}
class Compiler : public ICStubCompiler {
ICStub *firstMonitorStub_;
protected:
bool generateStubCode(MacroAssembler &masm);
public:
Compiler(JSContext *cx, ICStub *firstMonitorStub)
: ICStubCompiler(cx, ICStub::GetProp_ArgumentsCallee),
firstMonitorStub_(firstMonitorStub)
{}
ICStub *getStub(ICStubSpace *space) {
return ICGetProp_ArgumentsCallee::New(space, getStubCode(), firstMonitorStub_);
}
};
};
// SetProp
// JSOP_SETPROP
// JSOP_SETNAME

View File

@ -2419,9 +2419,14 @@ ArgumentsUseCanBeLazy(JSContext *cx, JSScript *script, MInstruction *ins, size_t
if (ins->isGetArgumentsObjectArg() && index == 0)
return true;
// arguments.length length can read fp->numActualArgs() directly.
if (ins->isCallGetProperty() && index == 0 && ins->toCallGetProperty()->name() == cx->names().length)
// arguments.length length can read fp->numActualArgs() directly and
// arguments.callee can read fp->callee() directly.
if (ins->isCallGetProperty() && index == 0 &&
(ins->toCallGetProperty()->name() == cx->names().length ||
ins->toCallGetProperty()->name() == cx->names().callee))
{
return true;
}
return false;
}

View File

@ -8598,6 +8598,10 @@ IonBuilder::jsop_getprop(PropertyName *name)
if (!getPropTryArgumentsLength(&emitted, obj) || emitted)
return emitted;
// Try to optimize arguments.callee.
if (!getPropTryArgumentsCallee(&emitted, obj, name) || emitted)
return emitted;
types::TemporaryTypeSet *types = bytecodeTypes(pc);
BarrierKind barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(),
obj, name, types);
@ -8662,17 +8666,34 @@ IonBuilder::jsop_getprop(PropertyName *name)
}
bool
IonBuilder::getPropTryArgumentsLength(bool *emitted, MDefinition *obj)
IonBuilder::checkIsDefinitelyOptimizedArguments(MDefinition *obj, bool *isOptimizedArgs)
{
JS_ASSERT(*emitted == false);
if (obj->type() != MIRType_MagicOptimizedArguments) {
if (script()->argumentsHasVarBinding() &&
obj->mightBeType(MIRType_MagicOptimizedArguments))
{
return abort("Type is not definitely lazy arguments.");
}
*isOptimizedArgs = false;
return true;
}
*isOptimizedArgs = true;
return true;
}
bool
IonBuilder::getPropTryArgumentsLength(bool *emitted, MDefinition *obj)
{
JS_ASSERT(*emitted == false);
bool isOptimizedArgs = false;
if (!checkIsDefinitelyOptimizedArguments(obj, &isOptimizedArgs))
return false;
if (!isOptimizedArgs)
return true;
if (JSOp(*pc) != JSOP_LENGTH)
return true;
@ -8692,6 +8713,27 @@ IonBuilder::getPropTryArgumentsLength(bool *emitted, MDefinition *obj)
return pushConstant(Int32Value(inlineCallInfo_->argv().length()));
}
bool
IonBuilder::getPropTryArgumentsCallee(bool *emitted, MDefinition *obj, PropertyName *name)
{
JS_ASSERT(*emitted == false);
bool isOptimizedArgs = false;
if (!checkIsDefinitelyOptimizedArguments(obj, &isOptimizedArgs))
return false;
if (!isOptimizedArgs)
return true;
if (name != names().callee)
return true;
obj->setImplicitlyUsedUnchecked();
current->push(getCallee());
*emitted = true;
return true;
}
bool
IonBuilder::getPropTryConstant(bool *emitted, MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *types)

View File

@ -399,7 +399,9 @@ class IonBuilder : public MIRGenerator
MDefinition *tryInnerizeWindow(MDefinition *obj);
// jsop_getprop() helpers.
bool checkIsDefinitelyOptimizedArguments(MDefinition *obj, bool *isOptimizedArgs);
bool getPropTryArgumentsLength(bool *emitted, MDefinition *obj);
bool getPropTryArgumentsCallee(bool *emitted, MDefinition *obj, PropertyName *name);
bool getPropTryConstant(bool *emitted, MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *types);
bool getPropTryDefiniteSlot(bool *emitted, MDefinition *obj, PropertyName *name,

View File

@ -221,8 +221,14 @@ GetPropertyOperation(JSContext *cx, InterpreterFrame *fp, HandleScript script, j
return true;
}
Rooted<GlobalObject*> global(cx, &fp->global());
RootedId id(cx, NameToId(script->getName(pc)));
if (id == NameToId(cx->names().callee) && IsOptimizedArguments(fp, lval.address())) {
vp.setObject(fp->callee());
return true;
}
Rooted<GlobalObject*> global(cx, &fp->global());
RootedObject obj(cx);
/* Optimize (.1).toString(). */