Bug 880085 - Unbreak run once closure optimizations, and don't treat named lambdas as run once closures, r=luke.

This commit is contained in:
Brian Hackett 2013-10-11 14:34:11 -06:00
parent aba7ac56ed
commit aba6876518
5 changed files with 29 additions and 7 deletions

View File

@ -454,6 +454,8 @@ frontend::CompileLazyFunction(JSContext *cx, LazyScript *lazy, const jschar *cha
script->directlyInsideEval = true;
if (lazy->usesArgumentsAndApply())
script->usesArgumentsAndApply = true;
if (lazy->hasBeenCloned())
script->hasBeenCloned = true;
BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, options.forEval,
/* evalCaller = */ NullPtr(), /* hasGlobalScope = */ true,
@ -461,6 +463,9 @@ frontend::CompileLazyFunction(JSContext *cx, LazyScript *lazy, const jschar *cha
if (!bce.init())
return false;
if (lazy->treatAsRunOnce())
bce.lazyRunOnceLambda = true;
return EmitFunctionScript(cx, &bce, pn->pn_body);
}

View File

@ -107,6 +107,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
hasSingletons(false),
emittingForInit(false),
emittingRunOnceLambda(false),
lazyRunOnceLambda(false),
insideEval(insideEval),
hasGlobalScope(hasGlobalScope),
emitterMode(emitterMode)
@ -2666,10 +2667,11 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo
* the script ends up running multiple times via foo.caller related
* shenanigans.
*/
bool runOnce = bce->parent &&
bce->parent->emittingRunOnceLambda &&
bool runOnce =
bce->isRunOnceLambda() &&
!funbox->argumentsHasLocalBinding() &&
!funbox->isGenerator();
!funbox->isGenerator() &&
!funbox->function()->name();
if (runOnce) {
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_RUNONCE) < 0)
@ -4788,9 +4790,7 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
bce->script->compileAndGo &&
fun->isInterpreted() &&
(bce->checkSingletonContext() ||
(!bce->isInLoop() &&
bce->parent &&
bce->parent->emittingRunOnceLambda));
(!bce->isInLoop() && bce->isRunOnceLambda()));
if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
return false;
@ -4801,6 +4801,8 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
scope = bce->sc->asFunctionBox()->function();
fun->lazyScript()->setParent(scope, bce->script->sourceObject());
}
if (bce->emittingRunOnceLambda)
fun->lazyScript()->setTreatAsRunOnce();
} else {
SharedContext *outersc = bce->sc;

View File

@ -124,6 +124,12 @@ struct BytecodeEmitter
bool emittingRunOnceLambda:1; /* true while emitting a lambda which is only
expected to run once. */
bool lazyRunOnceLambda:1; /* true while lazily emitting a script for
* a lambda which is only expected to run once. */
bool isRunOnceLambda() {
return (parent && parent->emittingRunOnceLambda) || lazyRunOnceLambda;
}
bool insideEval:1; /* True if compiling an eval-expression or a function
nested inside an eval. */

View File

@ -2942,6 +2942,7 @@ LazyScript::LazyScript(JSFunction *fun, void *table, uint32_t numFreeVariables,
directlyInsideEval_(false),
usesArgumentsAndApply_(false),
hasBeenCloned_(false),
treatAsRunOnce_(false),
begin_(begin),
end_(end),
lineno_(lineno),

View File

@ -1183,7 +1183,7 @@ class LazyScript : public gc::BarrieredCell<LazyScript>
uint32_t version_ : 8;
uint32_t numFreeVariables_ : 24;
uint32_t numInnerFunctions_ : 24;
uint32_t numInnerFunctions_ : 23;
uint32_t generatorKindBits_:2;
@ -1194,6 +1194,7 @@ class LazyScript : public gc::BarrieredCell<LazyScript>
uint32_t directlyInsideEval_:1;
uint32_t usesArgumentsAndApply_:1;
uint32_t hasBeenCloned_:1;
uint32_t treatAsRunOnce_:1;
// Source location for the script.
uint32_t begin_;
@ -1310,6 +1311,13 @@ class LazyScript : public gc::BarrieredCell<LazyScript>
hasBeenCloned_ = true;
}
bool treatAsRunOnce() const {
return treatAsRunOnce_;
}
void setTreatAsRunOnce() {
treatAsRunOnce_ = true;
}
ScriptSource *source() const {
return sourceObject()->source();
}