Bug 1003161 - Don't optimize arguments usage in scripts with aliased arguments, r=jandem.

This commit is contained in:
Brian Hackett 2014-05-01 06:13:10 -07:00
parent 766404390f
commit d9df1214c0
2 changed files with 47 additions and 3 deletions

View File

@ -0,0 +1,8 @@
function foo(a, b) {
function bar() {
return b;
}
return arguments[0] + arguments[1] + bar();
}
foo(1, 2);

View File

@ -2371,7 +2371,8 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
}
static bool
ArgumentsUseCanBeLazy(JSContext *cx, JSScript *script, MInstruction *ins, size_t index)
ArgumentsUseCanBeLazy(JSContext *cx, JSScript *script, MInstruction *ins, size_t index,
bool *argumentsContentsObserved)
{
// We can read the frame's arguments directly for f.apply(x, arguments).
if (ins->isCall()) {
@ -2379,13 +2380,16 @@ ArgumentsUseCanBeLazy(JSContext *cx, JSScript *script, MInstruction *ins, size_t
ins->toCall()->numActualArgs() == 2 &&
index == MCall::IndexOfArgument(1))
{
*argumentsContentsObserved = true;
return true;
}
}
// arguments[i] can read fp->canonicalActualArg(i) directly.
if (ins->isCallGetElement() && index == 0)
if (ins->isCallGetElement() && index == 0) {
*argumentsContentsObserved = true;
return true;
}
// arguments.length length can read fp->numActualArgs() directly.
if (ins->isCallGetProperty() && index == 0 && ins->toCallGetProperty()->name() == cx->names().length)
@ -2408,6 +2412,26 @@ jit::AnalyzeArgumentsUsage(JSContext *cx, JSScript *scriptArg)
// and also simplifies handling of early returns.
script->setNeedsArgsObj(true);
// Always construct arguments objects when in debug mode and for generator
// scripts (generators can be suspended when speculation fails).
//
// FIXME: Don't build arguments for ES6 generator expressions.
if (cx->compartment()->debugMode() || script->isGenerator())
return true;
// If the script has dynamic name accesses which could reach 'arguments',
// the parser will already have checked to ensure there are no explicit
// uses of 'arguments' in the function. If there are such uses, the script
// will be marked as definitely needing an arguments object.
//
// New accesses on 'arguments' can occur through 'eval' or the debugger
// statement. In the former case, we will dynamically detect the use and
// mark the arguments optimization as having failed.
if (script->bindingsAccessedDynamically()) {
script->setNeedsArgsObj(false);
return true;
}
if (!jit::IsIonEnabled(cx) || !script->compileAndGo())
return true;
@ -2470,6 +2494,8 @@ jit::AnalyzeArgumentsUsage(JSContext *cx, JSScript *scriptArg)
MDefinition *argumentsValue = graph.begin()->getSlot(info.argsObjSlot());
bool argumentsContentsObserved = false;
for (MUseDefIterator uses(argumentsValue); uses; uses++) {
MDefinition *use = uses.def();
@ -2477,10 +2503,20 @@ jit::AnalyzeArgumentsUsage(JSContext *cx, JSScript *scriptArg)
if (!use->isInstruction())
return true;
if (!ArgumentsUseCanBeLazy(cx, script, use->toInstruction(), uses.index()))
if (!ArgumentsUseCanBeLazy(cx, script, use->toInstruction(), uses.index(),
&argumentsContentsObserved))
{
return true;
}
}
// If a script explicitly accesses the contents of 'arguments', and has
// formals which may be stored as part of a call object, don't use lazy
// arguments. The compiler can then assume that accesses through
// arguments[i] will be on unaliased variables.
if (script->funHasAnyAliasedFormal() && argumentsContentsObserved)
return true;
script->setNeedsArgsObj(false);
return true;
}