Bug 883439 - Lazily parse scripts defined within catch blocks, r=luke.

This commit is contained in:
Brian Hackett 2013-06-15 07:54:22 -06:00
Родитель 986261c995
Коммит 0054473e24
6 изменённых файлов: 40 добавлений и 29 удалений

Просмотреть файл

@ -340,20 +340,21 @@ frontend::CompileLazyFunction(JSContext *cx, HandleFunction fun, LazyScript *laz
Parser<FullParseHandler> parser(cx, options, chars, length,
/* foldConstants = */ true, NULL, lazy);
RootedObject enclosingScope(cx, lazy->parentFunction());
uint32_t staticLevel = lazy->staticLevel(cx);
ParseNode *pn = parser.standaloneLazyFunction(fun, lazy->staticLevel(), lazy->strict());
ParseNode *pn = parser.standaloneLazyFunction(fun, staticLevel, lazy->strict());
if (!pn)
return false;
if (!NameFunctions(cx, pn))
return false;
RootedObject enclosingScope(cx, lazy->enclosingScope());
JS::RootedScriptSource sourceObject(cx, lazy->sourceObject());
JS_ASSERT(sourceObject);
Rooted<JSScript*> script(cx, JSScript::Create(cx, enclosingScope, false,
options, lazy->staticLevel(),
options, staticLevel,
sourceObject, lazy->begin(), lazy->end()));
if (!script)
return false;

Просмотреть файл

@ -1156,6 +1156,10 @@ TryConvertFreeName(BytecodeEmitter *bce, ParseNode *pn)
RootedObject outerScope(bce->sc->context, bce->script->enclosingStaticScope());
for (StaticScopeIter ssi(bce->sc->context, outerScope); !ssi.done(); ssi++) {
if (ssi.type() != StaticScopeIter::FUNCTION) {
if (ssi.type() == StaticScopeIter::BLOCK) {
// Use generic ops if a catch block is encountered.
return false;
}
if (ssi.hasDynamicScopeObject())
hops++;
continue;
@ -4504,8 +4508,10 @@ EmitFunc(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (fun->isInterpretedLazy()) {
if (!fun->lazyScript()->sourceObject()) {
JSFunction *parent = bce->sc->isFunctionBox() ? bce->sc->asFunctionBox()->function() : NULL;
fun->lazyScript()->setParent(parent, bce->script->sourceObject(), bce->script->originPrincipals);
JSObject *scope = bce->blockChain;
if (!scope && bce->sc->isFunctionBox())
scope = bce->sc->asFunctionBox()->function();
fun->lazyScript()->setParent(scope, bce->script->sourceObject(), bce->script->originPrincipals);
}
} else {
SharedContext *outersc = bce->sc;

Просмотреть файл

@ -2065,11 +2065,6 @@ Parser<FullParseHandler>::functionArgsAndBody(ParseNode *pn, HandleFunction fun,
if (!funbox)
return false;
// Disable lazy parsing if any functions are defined within a scope
// statement. Free names in the inner functions will be bound incorrectly.
if (pc->topScopeStmt)
handler.disableSyntaxParser();
// Try a syntax parse for this inner function.
do {
Parser<SyntaxParseHandler> *parser = handler.syntaxParser;
@ -2151,11 +2146,6 @@ Parser<SyntaxParseHandler>::functionArgsAndBody(Node pn, HandleFunction fun,
*becameStrict = false;
ParseContext<SyntaxParseHandler> *outerpc = pc;
// As from a full parse handler, abort if functions are defined within
// lexical scopes.
if (pc->topScopeStmt)
return abortIfSyntaxParser();
// Create box for fun->object early to protect against last-ditch GC.
FunctionBox *funbox = newFunctionBox(fun, pc, strict);
if (!funbox)

Просмотреть файл

@ -34,3 +34,12 @@ function test() {
(function(x) { return !(x) })(0/0)
}
}
testCatch(15);
function testCatch(y) {
try {
throw 5;
} catch(ex) {
(function(x) { assertEq(x + y + ex, 25); })(5)
}
}

Просмотреть файл

@ -2774,8 +2774,8 @@ LazyScript::markChildren(JSTracer *trc)
if (sourceObject_)
MarkObject(trc, &sourceObject_, "sourceObject");
if (parentFunction_)
MarkObject(trc, &parentFunction_, "parentFunction");
if (enclosingScope_)
MarkObject(trc, &enclosingScope_, "enclosingScope");
if (script_)
MarkScript(trc, &script_, "realScript");
@ -2948,7 +2948,7 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
LazyScript::LazyScript(void *table, uint32_t numFreeVariables, uint32_t numInnerFunctions,
JSVersion version, uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
: script_(NULL),
parentFunction_(NULL),
enclosingScope_(NULL),
sourceObject_(NULL),
table_(table),
originPrincipals_(NULL),
@ -2978,11 +2978,11 @@ LazyScript::initScript(JSScript *script)
}
void
LazyScript::setParent(JSFunction *parentFunction, ScriptSourceObject *sourceObject,
LazyScript::setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject,
JSPrincipals *originPrincipals)
{
JS_ASSERT(sourceObject && !sourceObject_ && !parentFunction_ && !originPrincipals_);
parentFunction_ = parentFunction;
JS_ASSERT(sourceObject && !sourceObject_ && !enclosingScope_ && !originPrincipals_);
enclosingScope_ = enclosingScope;
sourceObject_ = sourceObject;
originPrincipals_ = originPrincipals;
if (originPrincipals)
@ -3019,9 +3019,14 @@ LazyScript::Create(JSContext *cx, uint32_t numFreeVariables, uint32_t numInnerFu
begin, end, lineno, column);
}
uint32_t LazyScript::staticLevel() const
uint32_t
LazyScript::staticLevel(JSContext *cx) const
{
return parentFunction() ? parentFunction()->nonLazyScript()->staticLevel + 1 : 1;
for (StaticScopeIter ssi(cx, enclosingScope()); !ssi.done(); ssi++) {
if (ssi.type() == StaticScopeIter::FUNCTION)
return ssi.funScript()->staticLevel + 1;
}
return 1;
}
void

Просмотреть файл

@ -1110,8 +1110,8 @@ class LazyScript : public js::gc::Cell
// pointer to the result.
HeapPtrScript script_;
// Immediate parent in which the script is nested, or NULL.
HeapPtrFunction parentFunction_;
// Function or block chain in which the script is nested, or NULL.
HeapPtrObject enclosingScope_;
// Source code object, or NULL if the script in which this is nested has
// not been compiled yet.
@ -1157,8 +1157,8 @@ class LazyScript : public js::gc::Cell
return script_;
}
JSFunction *parentFunction() const {
return parentFunction_;
JSObject *enclosingScope() const {
return enclosingScope_;
}
ScriptSourceObject *sourceObject() const;
JSPrincipals *originPrincipals() const {
@ -1169,7 +1169,7 @@ class LazyScript : public js::gc::Cell
return (version_ == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(version_);
}
void setParent(JSFunction *parentFunction, ScriptSourceObject *sourceObject,
void setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject,
JSPrincipals *originPrincipals);
uint32_t numFreeVariables() const {
@ -1244,7 +1244,7 @@ class LazyScript : public js::gc::Cell
return column_;
}
uint32_t staticLevel() const;
uint32_t staticLevel(JSContext *cx) const;
Zone *zone() const {
return Cell::tenuredZone();