diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 9a3789d4b1fc..588f46897187 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -340,20 +340,21 @@ frontend::CompileLazyFunction(JSContext *cx, HandleFunction fun, LazyScript *laz Parser 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 script(cx, JSScript::Create(cx, enclosingScope, false, - options, lazy->staticLevel(), + options, staticLevel, sourceObject, lazy->begin(), lazy->end())); if (!script) return false; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 8d6fbb7be16b..dc3522c1aac7 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -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; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index fca697549035..bd9a20930127 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2065,11 +2065,6 @@ Parser::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 *parser = handler.syntaxParser; @@ -2151,11 +2146,6 @@ Parser::functionArgsAndBody(Node pn, HandleFunction fun, *becameStrict = false; ParseContext *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) diff --git a/js/src/jit-test/tests/basic/lazyparse.js b/js/src/jit-test/tests/basic/lazyparse.js index 0aff8fe78fab..b878c6302e23 100644 --- a/js/src/jit-test/tests/basic/lazyparse.js +++ b/js/src/jit-test/tests/basic/lazyparse.js @@ -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) + } +} diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 047322749b61..b6c8b1833cd4 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -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 diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 82b3232fd2e8..1ab4743ff1df 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -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();