mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
Bug 1030985
- Optimize arguments.callee. (r=h4writer)
This commit is contained in:
parent
481f2ae7f8
commit
2457dac324
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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(). */
|
||||
|
Loading…
Reference in New Issue
Block a user