| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index 4947790395f3c431db7ef1ef68f30d47fccb8e5b..ccab7ec64c1a697d5f36aa59152dec389f9f4e25 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -542,6 +542,7 @@ Parser::Parser(CompilationInfo* info)
|
| scanner_(isolate_->unicode_cache()),
|
| reusable_preparser_(NULL),
|
| top_scope_(NULL),
|
| + original_scope_(NULL),
|
| current_function_state_(NULL),
|
| target_stack_(NULL),
|
| extension_(info->extension()),
|
| @@ -622,6 +623,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
|
| if (!info->context().is_null()) {
|
| scope = Scope::DeserializeScopeChain(*info->context(), scope, zone());
|
| }
|
| + original_scope_ = scope;
|
| if (info->is_eval()) {
|
| if (!scope->is_global_scope() || info->language_mode() != CLASSIC_MODE) {
|
| scope = NewScope(scope, EVAL_SCOPE);
|
| @@ -749,6 +751,7 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
|
| scope = Scope::DeserializeScopeChain(info()->closure()->context(), scope,
|
| zone());
|
| }
|
| + original_scope_ = scope;
|
| FunctionState function_state(this, scope, isolate());
|
| ASSERT(scope->language_mode() != STRICT_MODE || !info()->is_classic_mode());
|
| ASSERT(scope->language_mode() != EXTENDED_MODE ||
|
| @@ -4279,10 +4282,38 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
| // Function declarations are function scoped in normal mode, so they are
|
| // hoisted. In harmony block scoping mode they are block scoped, so they
|
| // are not hoisted.
|
| + //
|
| + // One tricky case are function declarations in a local sloppy-mode eval:
|
| + // their declaration is hoisted, but they still see the local scope. E.g.,
|
| + //
|
| + // function() {
|
| + // var x = 0
|
| + // try { throw 1 } catch (x) { eval("function g() { return x }") }
|
| + // return g()
|
| + // }
|
| + //
|
| + // needs to return 1. To distinguish such cases, we need to detect
|
| + // (1) whether a function stems from a sloppy eval, and
|
| + // (2) whether it actually hoists across the eval.
|
| + // Unfortunately, we do not represent sloppy eval scopes, so we do not have
|
| + // either information available directly, especially not when lazily compiling
|
| + // a function like 'g'. We hence rely on the following invariants:
|
| + // - (1) is the case iff the innermost scope of the deserialized scope chain
|
| + // under which we compile is _not_ a declaration scope. This holds because
|
| + // in all normal cases, function declarations are fully hoisted to a
|
| + // declaration scope and compiled relative to that.
|
| + // - (2) is the case iff the current declaration scope is still the original
|
| + // one relative to the deserialized scope chain. Otherwise we must be
|
| + // compiling a function in an inner declaration scope in the eval, e.g. a
|
| + // nested function, and hoisting works normally relative to that.
|
| + Scope* declaration_scope = top_scope_->DeclarationScope();
|
| + Scope* original_declaration_scope = original_scope_->DeclarationScope();
|
| Scope* scope =
|
| - (function_type == FunctionLiteral::DECLARATION && !is_extended_mode())
|
| - ? NewScope(top_scope_->DeclarationScope(), FUNCTION_SCOPE)
|
| - : NewScope(top_scope_, FUNCTION_SCOPE);
|
| + function_type == FunctionLiteral::DECLARATION && !is_extended_mode() &&
|
| + (original_scope_ == original_declaration_scope ||
|
| + declaration_scope != original_declaration_scope)
|
| + ? NewScope(declaration_scope, FUNCTION_SCOPE)
|
| + : NewScope(top_scope_, FUNCTION_SCOPE);
|
| ZoneList<Statement*>* body = NULL;
|
| int materialized_literal_count = -1;
|
| int expected_property_count = -1;
|
|
|