diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 059408ba152..5d04b17b4e2 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -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); } diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 8af8e3fe31e..41321641b91 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -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; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 1711a47e548..b1dab973fde 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -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. */ diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index d994bc3e323..255098796cc 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -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), diff --git a/js/src/jsscript.h b/js/src/jsscript.h index d1f98ed84e7..95f660dcfd9 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1183,7 +1183,7 @@ class LazyScript : public gc::BarrieredCell 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 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 hasBeenCloned_ = true; } + bool treatAsRunOnce() const { + return treatAsRunOnce_; + } + void setTreatAsRunOnce() { + treatAsRunOnce_ = true; + } + ScriptSource *source() const { return sourceObject()->source(); }