Commit 51685002 authored by marja's avatar marja Committed by Commit bot

Revert of Put Scopes into temporary Zone (patchset #12 id:220001 of...

Revert of Put Scopes into temporary Zone (patchset #12 id:220001 of https://codereview.chromium.org/2193793002/ )

Reason for revert:
Broke Node.js tests (test-require-dot etc.)

Original issue's description:
> Put Scopes into temporary Zone
>
> When parsing a eagerly-parsed-but-lazily-compiled function, we
> used to put some of its AST nodes into a discardable Zone. This
> CL puts the function Scope, its inner Scopes and the related AST
> nodes (Declarations, VariableProxys) into the temporary Zone
> too. This reduces peak memory usage and enables future work to
> keep the temporary Zone around for later compilation.
>
> BUG=
>
> Committed: https://crrev.com/eaebdd858b466057ccc39894a172c9b66868e8f7
> Cr-Commit-Position: refs/heads/master@{#38232}

TBR=adamk@chromium.org,titzer@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=

Review-Url: https://codereview.chromium.org/2205013002
Cr-Commit-Position: refs/heads/master@{#38258}
parent 3eab4e87
......@@ -204,18 +204,6 @@ VariableProxy::VariableProxy(Zone* zone, const AstRawString* name,
raw_name_(name),
next_unresolved_(nullptr) {}
VariableProxy::VariableProxy(Zone* zone, const VariableProxy* copy_from)
: Expression(zone, copy_from->position(), kVariableProxy),
bit_field_(copy_from->bit_field_),
end_position_(copy_from->end_position_),
next_unresolved_(nullptr) {
if (copy_from->is_resolved()) {
var_ = copy_from->var_;
} else {
raw_name_ = copy_from->raw_name_;
}
}
void VariableProxy::BindTo(Variable* var) {
DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name());
set_var(var);
......
......@@ -1690,7 +1690,6 @@ class VariableProxy final : public Expression {
VariableProxy(Zone* zone, const AstRawString* name,
Variable::Kind variable_kind, int start_position,
int end_position);
VariableProxy(Zone* zone, const VariableProxy* copy_from);
static int parent_num_ids() { return Expression::num_ids(); }
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
......@@ -3044,22 +3043,27 @@ class AstVisitor BASE_EMBEDDED {
class AstNodeFactory final BASE_EMBEDDED {
public:
explicit AstNodeFactory(AstValueFactory* ast_value_factory)
: zone_(nullptr), ast_value_factory_(ast_value_factory) {
: local_zone_(nullptr),
parser_zone_(nullptr),
ast_value_factory_(ast_value_factory) {
if (ast_value_factory != nullptr) {
zone_ = ast_value_factory->zone();
local_zone_ = ast_value_factory->zone();
parser_zone_ = ast_value_factory->zone();
}
}
AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
void set_ast_value_factory(AstValueFactory* ast_value_factory) {
ast_value_factory_ = ast_value_factory;
zone_ = ast_value_factory->zone();
local_zone_ = ast_value_factory->zone();
parser_zone_ = ast_value_factory->zone();
}
VariableDeclaration* NewVariableDeclaration(VariableProxy* proxy,
VariableMode mode, Scope* scope,
int pos) {
return new (zone_) VariableDeclaration(zone_, proxy, mode, scope, pos);
return new (parser_zone_)
VariableDeclaration(parser_zone_, proxy, mode, scope, pos);
}
FunctionDeclaration* NewFunctionDeclaration(VariableProxy* proxy,
......@@ -3067,18 +3071,19 @@ class AstNodeFactory final BASE_EMBEDDED {
FunctionLiteral* fun,
Scope* scope,
int pos) {
return new (zone_) FunctionDeclaration(zone_, proxy, mode, fun, scope, pos);
return new (parser_zone_)
FunctionDeclaration(parser_zone_, proxy, mode, fun, scope, pos);
}
Block* NewBlock(ZoneList<const AstRawString*>* labels, int capacity,
bool ignore_completion_value, int pos) {
return new (zone_)
Block(zone_, labels, capacity, ignore_completion_value, pos);
return new (local_zone_)
Block(local_zone_, labels, capacity, ignore_completion_value, pos);
}
#define STATEMENT_WITH_LABELS(NodeType) \
NodeType* New##NodeType(ZoneList<const AstRawString*>* labels, int pos) { \
return new (zone_) NodeType(zone_, labels, pos); \
return new (local_zone_) NodeType(local_zone_, labels, pos); \
}
STATEMENT_WITH_LABELS(DoWhileStatement)
STATEMENT_WITH_LABELS(WhileStatement)
......@@ -3091,10 +3096,10 @@ class AstNodeFactory final BASE_EMBEDDED {
int pos) {
switch (visit_mode) {
case ForEachStatement::ENUMERATE: {
return new (zone_) ForInStatement(zone_, labels, pos);
return new (local_zone_) ForInStatement(local_zone_, labels, pos);
}
case ForEachStatement::ITERATE: {
return new (zone_) ForOfStatement(zone_, labels, pos);
return new (local_zone_) ForOfStatement(local_zone_, labels, pos);
}
}
UNREACHABLE();
......@@ -3102,41 +3107,42 @@ class AstNodeFactory final BASE_EMBEDDED {
}
ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) {
return new (zone_) ExpressionStatement(zone_, expression, pos);
return new (local_zone_) ExpressionStatement(local_zone_, expression, pos);
}
ContinueStatement* NewContinueStatement(IterationStatement* target, int pos) {
return new (zone_) ContinueStatement(zone_, target, pos);
return new (local_zone_) ContinueStatement(local_zone_, target, pos);
}
BreakStatement* NewBreakStatement(BreakableStatement* target, int pos) {
return new (zone_) BreakStatement(zone_, target, pos);
return new (local_zone_) BreakStatement(local_zone_, target, pos);
}
ReturnStatement* NewReturnStatement(Expression* expression, int pos) {
return new (zone_) ReturnStatement(zone_, expression, pos);
return new (local_zone_) ReturnStatement(local_zone_, expression, pos);
}
WithStatement* NewWithStatement(Scope* scope,
Expression* expression,
Statement* statement,
int pos) {
return new (zone_) WithStatement(zone_, scope, expression, statement, pos);
return new (local_zone_)
WithStatement(local_zone_, scope, expression, statement, pos);
}
IfStatement* NewIfStatement(Expression* condition,
Statement* then_statement,
Statement* else_statement,
int pos) {
return new (zone_)
IfStatement(zone_, condition, then_statement, else_statement, pos);
return new (local_zone_) IfStatement(local_zone_, condition, then_statement,
else_statement, pos);
}
TryCatchStatement* NewTryCatchStatement(Block* try_block, Scope* scope,
Variable* variable,
Block* catch_block, int pos) {
return new (zone_)
TryCatchStatement(zone_, try_block, scope, variable, catch_block,
return new (local_zone_)
TryCatchStatement(local_zone_, try_block, scope, variable, catch_block,
HandlerTable::CAUGHT, pos);
}
......@@ -3145,8 +3151,8 @@ class AstNodeFactory final BASE_EMBEDDED {
Variable* variable,
Block* catch_block,
int pos) {
return new (zone_)
TryCatchStatement(zone_, try_block, scope, variable, catch_block,
return new (local_zone_)
TryCatchStatement(local_zone_, try_block, scope, variable, catch_block,
HandlerTable::UNCAUGHT, pos);
}
......@@ -3155,81 +3161,88 @@ class AstNodeFactory final BASE_EMBEDDED {
Variable* variable,
Block* catch_block,
int pos) {
return new (zone_)
TryCatchStatement(zone_, try_block, scope, variable, catch_block,
return new (local_zone_)
TryCatchStatement(local_zone_, try_block, scope, variable, catch_block,
HandlerTable::PROMISE, pos);
}
TryFinallyStatement* NewTryFinallyStatement(Block* try_block,
Block* finally_block, int pos) {
return new (zone_)
TryFinallyStatement(zone_, try_block, finally_block, pos);
return new (local_zone_)
TryFinallyStatement(local_zone_, try_block, finally_block, pos);
}
DebuggerStatement* NewDebuggerStatement(int pos) {
return new (zone_) DebuggerStatement(zone_, pos);
return new (local_zone_) DebuggerStatement(local_zone_, pos);
}
EmptyStatement* NewEmptyStatement(int pos) {
return new (zone_) EmptyStatement(zone_, pos);
return new (local_zone_) EmptyStatement(local_zone_, pos);
}
SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(
Statement* statement, Scope* scope) {
return new (zone_) SloppyBlockFunctionStatement(zone_, statement, scope);
return new (parser_zone_)
SloppyBlockFunctionStatement(parser_zone_, statement, scope);
}
CaseClause* NewCaseClause(
Expression* label, ZoneList<Statement*>* statements, int pos) {
return new (zone_) CaseClause(zone_, label, statements, pos);
return new (local_zone_) CaseClause(local_zone_, label, statements, pos);
}
Literal* NewStringLiteral(const AstRawString* string, int pos) {
return new (zone_)
Literal(zone_, ast_value_factory_->NewString(string), pos);
return new (local_zone_)
Literal(local_zone_, ast_value_factory_->NewString(string), pos);
}
// A JavaScript symbol (ECMA-262 edition 6).
Literal* NewSymbolLiteral(const char* name, int pos) {
return new (zone_) Literal(zone_, ast_value_factory_->NewSymbol(name), pos);
return new (local_zone_)
Literal(local_zone_, ast_value_factory_->NewSymbol(name), pos);
}
Literal* NewNumberLiteral(double number, int pos, bool with_dot = false) {
return new (zone_)
Literal(zone_, ast_value_factory_->NewNumber(number, with_dot), pos);
return new (local_zone_) Literal(
local_zone_, ast_value_factory_->NewNumber(number, with_dot), pos);
}
Literal* NewSmiLiteral(int number, int pos) {
return new (zone_) Literal(zone_, ast_value_factory_->NewSmi(number), pos);
return new (local_zone_)
Literal(local_zone_, ast_value_factory_->NewSmi(number), pos);
}
Literal* NewBooleanLiteral(bool b, int pos) {
return new (zone_) Literal(zone_, ast_value_factory_->NewBoolean(b), pos);
return new (local_zone_)
Literal(local_zone_, ast_value_factory_->NewBoolean(b), pos);
}
Literal* NewNullLiteral(int pos) {
return new (zone_) Literal(zone_, ast_value_factory_->NewNull(), pos);
return new (local_zone_)
Literal(local_zone_, ast_value_factory_->NewNull(), pos);
}
Literal* NewUndefinedLiteral(int pos) {
return new (zone_) Literal(zone_, ast_value_factory_->NewUndefined(), pos);
return new (local_zone_)
Literal(local_zone_, ast_value_factory_->NewUndefined(), pos);
}
Literal* NewTheHoleLiteral(int pos) {
return new (zone_) Literal(zone_, ast_value_factory_->NewTheHole(), pos);
return new (local_zone_)
Literal(local_zone_, ast_value_factory_->NewTheHole(), pos);
}
ObjectLiteral* NewObjectLiteral(
ZoneList<ObjectLiteral::Property*>* properties, int literal_index,
uint32_t boilerplate_properties, int pos) {
return new (zone_) ObjectLiteral(zone_, properties, literal_index,
boilerplate_properties, pos);
return new (local_zone_) ObjectLiteral(
local_zone_, properties, literal_index, boilerplate_properties, pos);
}
ObjectLiteral::Property* NewObjectLiteralProperty(
Expression* key, Expression* value, ObjectLiteralProperty::Kind kind,
bool is_static, bool is_computed_name) {
return new (zone_)
return new (local_zone_)
ObjectLiteral::Property(key, value, kind, is_static, is_computed_name);
}
......@@ -3237,32 +3250,35 @@ class AstNodeFactory final BASE_EMBEDDED {
Expression* value,
bool is_static,
bool is_computed_name) {
return new (zone_) ObjectLiteral::Property(ast_value_factory_, key, value,
is_static, is_computed_name);
return new (local_zone_) ObjectLiteral::Property(
ast_value_factory_, key, value, is_static, is_computed_name);
}
RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern, int flags,
int literal_index, int pos) {
return new (zone_) RegExpLiteral(zone_, pattern, flags, literal_index, pos);
return new (local_zone_)
RegExpLiteral(local_zone_, pattern, flags, literal_index, pos);
}
ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
int literal_index,
int pos) {
return new (zone_) ArrayLiteral(zone_, values, -1, literal_index, pos);
return new (local_zone_)
ArrayLiteral(local_zone_, values, -1, literal_index, pos);
}
ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
int first_spread_index, int literal_index,
int pos) {
return new (zone_)
ArrayLiteral(zone_, values, first_spread_index, literal_index, pos);
return new (local_zone_) ArrayLiteral(
local_zone_, values, first_spread_index, literal_index, pos);
}
VariableProxy* NewVariableProxy(Variable* var,
int start_position = kNoSourcePosition,
int end_position = kNoSourcePosition) {
return new (zone_) VariableProxy(zone_, var, start_position, end_position);
return new (parser_zone_)
VariableProxy(parser_zone_, var, start_position, end_position);
}
VariableProxy* NewVariableProxy(const AstRawString* name,
......@@ -3270,89 +3286,87 @@ class AstNodeFactory final BASE_EMBEDDED {
int start_position = kNoSourcePosition,
int end_position = kNoSourcePosition) {
DCHECK_NOT_NULL(name);
return new (zone_)
VariableProxy(zone_, name, variable_kind, start_position, end_position);
}
// Recreates the VariableProxy in this Zone.
VariableProxy* CopyVariableProxy(VariableProxy* proxy) {
return new (zone_) VariableProxy(zone_, proxy);
return new (parser_zone_) VariableProxy(parser_zone_, name, variable_kind,
start_position, end_position);
}
Property* NewProperty(Expression* obj, Expression* key, int pos) {
return new (zone_) Property(zone_, obj, key, pos);
return new (local_zone_) Property(local_zone_, obj, key, pos);
}
Call* NewCall(Expression* expression,
ZoneList<Expression*>* arguments,
int pos) {
return new (zone_) Call(zone_, expression, arguments, pos);
return new (local_zone_) Call(local_zone_, expression, arguments, pos);
}
CallNew* NewCallNew(Expression* expression,
ZoneList<Expression*>* arguments,
int pos) {
return new (zone_) CallNew(zone_, expression, arguments, pos);
return new (local_zone_) CallNew(local_zone_, expression, arguments, pos);
}
CallRuntime* NewCallRuntime(Runtime::FunctionId id,
ZoneList<Expression*>* arguments, int pos) {
return new (zone_)
CallRuntime(zone_, Runtime::FunctionForId(id), arguments, pos);
return new (local_zone_)
CallRuntime(local_zone_, Runtime::FunctionForId(id), arguments, pos);
}
CallRuntime* NewCallRuntime(const Runtime::Function* function,
ZoneList<Expression*>* arguments, int pos) {
return new (zone_) CallRuntime(zone_, function, arguments, pos);
return new (local_zone_) CallRuntime(local_zone_, function, arguments, pos);
}
CallRuntime* NewCallRuntime(int context_index,
ZoneList<Expression*>* arguments, int pos) {
return new (zone_) CallRuntime(zone_, context_index, arguments, pos);
return new (local_zone_)
CallRuntime(local_zone_, context_index, arguments, pos);
}
UnaryOperation* NewUnaryOperation(Token::Value op,
Expression* expression,
int pos) {
return new (zone_) UnaryOperation(zone_, op, expression, pos);
return new (local_zone_) UnaryOperation(local_zone_, op, expression, pos);
}
BinaryOperation* NewBinaryOperation(Token::Value op,
Expression* left,
Expression* right,
int pos) {
return new (zone_) BinaryOperation(zone_, op, left, right, pos);
return new (local_zone_) BinaryOperation(local_zone_, op, left, right, pos);
}
CountOperation* NewCountOperation(Token::Value op,
bool is_prefix,
Expression* expr,
int pos) {
return new (zone_) CountOperation(zone_, op, is_prefix, expr, pos);
return new (local_zone_)
CountOperation(local_zone_, op, is_prefix, expr, pos);
}
CompareOperation* NewCompareOperation(Token::Value op,
Expression* left,
Expression* right,
int pos) {
return new (zone_) CompareOperation(zone_, op, left, right, pos);
return new (local_zone_)
CompareOperation(local_zone_, op, left, right, pos);
}
Spread* NewSpread(Expression* expression, int pos, int expr_pos) {
return new (zone_) Spread(zone_, expression, pos, expr_pos);
return new (local_zone_) Spread(local_zone_, expression, pos, expr_pos);
}
Conditional* NewConditional(Expression* condition,
Expression* then_expression,
Expression* else_expression,
int position) {
return new (zone_) Conditional(zone_, condition, then_expression,
else_expression, position);
return new (local_zone_) Conditional(
local_zone_, condition, then_expression, else_expression, position);
}
RewritableExpression* NewRewritableExpression(Expression* expression) {
DCHECK_NOT_NULL(expression);
return new (zone_) RewritableExpression(zone_, expression);
return new (local_zone_) RewritableExpression(local_zone_, expression);
}
Assignment* NewAssignment(Token::Value op,
......@@ -3360,7 +3374,8 @@ class AstNodeFactory final BASE_EMBEDDED {
Expression* value,
int pos) {
DCHECK(Token::IsAssignmentOp(op));
Assignment* assign = new (zone_) Assignment(zone_, op, target, value, pos);
Assignment* assign =
new (local_zone_) Assignment(local_zone_, op, target, value, pos);
if (assign->is_compound()) {
DCHECK(Token::IsAssignmentOp(op));
assign->binary_operation_ =
......@@ -3372,12 +3387,12 @@ class AstNodeFactory final BASE_EMBEDDED {
Yield* NewYield(Expression* generator_object, Expression* expression, int pos,
Yield::OnException on_exception) {
if (!expression) expression = NewUndefinedLiteral(pos);
return new (zone_)
Yield(zone_, generator_object, expression, pos, on_exception);
return new (local_zone_)
Yield(local_zone_, generator_object, expression, pos, on_exception);
}
Throw* NewThrow(Expression* exception, int pos) {
return new (zone_) Throw(zone_, exception, pos);
return new (local_zone_) Throw(local_zone_, exception, pos);
}
FunctionLiteral* NewFunctionLiteral(
......@@ -3388,8 +3403,8 @@ class AstNodeFactory final BASE_EMBEDDED {
FunctionLiteral::FunctionType function_type,
FunctionLiteral::EagerCompileHint eager_compile_hint, FunctionKind kind,
int position) {
return new (zone_) FunctionLiteral(
zone_, name, ast_value_factory_, scope, body,
return new (local_zone_) FunctionLiteral(
local_zone_, name, ast_value_factory_, scope, body,
materialized_literal_count, expected_property_count, parameter_count,
function_type, has_duplicate_parameters, eager_compile_hint, kind,
position, true);
......@@ -3401,9 +3416,9 @@ class AstNodeFactory final BASE_EMBEDDED {
FunctionLiteral* NewScriptOrEvalFunctionLiteral(
Scope* scope, ZoneList<Statement*>* body, int materialized_literal_count,
int expected_property_count) {
return new (zone_) FunctionLiteral(
zone_, ast_value_factory_->empty_string(), ast_value_factory_, scope,
body, materialized_literal_count, expected_property_count, 0,
return new (local_zone_) FunctionLiteral(
local_zone_, ast_value_factory_->empty_string(), ast_value_factory_,
scope, body, materialized_literal_count, expected_property_count, 0,
FunctionLiteral::kAnonymousExpression,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kShouldLazyCompile, FunctionKind::kNormalFunction, 0,
......@@ -3414,58 +3429,59 @@ class AstNodeFactory final BASE_EMBEDDED {
FunctionLiteral* constructor,
ZoneList<ObjectLiteral::Property*>* properties,
int start_position, int end_position) {
return new (zone_) ClassLiteral(zone_, proxy, extends, constructor,
properties, start_position, end_position);
return new (local_zone_)
ClassLiteral(local_zone_, proxy, extends, constructor, properties,
start_position, end_position);
}
NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name,
v8::Extension* extension,
int pos) {
return new (zone_) NativeFunctionLiteral(zone_, name, extension, pos);
return new (local_zone_)
NativeFunctionLiteral(local_zone_, name, extension, pos);
}
DoExpression* NewDoExpression(Block* block, Variable* result_var, int pos) {
VariableProxy* result = NewVariableProxy(result_var, pos);
return new (zone_) DoExpression(zone_, block, result, pos);
return new (local_zone_) DoExpression(local_zone_, block, result, pos);
}
ThisFunction* NewThisFunction(int pos) {
return new (zone_) ThisFunction(zone_, pos);
return new (local_zone_) ThisFunction(local_zone_, pos);
}
SuperPropertyReference* NewSuperPropertyReference(VariableProxy* this_var,
Expression* home_object,
int pos) {
return new (zone_)
SuperPropertyReference(zone_, this_var, home_object, pos);
return new (local_zone_)
SuperPropertyReference(local_zone_, this_var, home_object, pos);
}
SuperCallReference* NewSuperCallReference(VariableProxy* this_var,
VariableProxy* new_target_var,
VariableProxy* this_function_var,
int pos) {
return new (zone_) SuperCallReference(zone_, this_var, new_target_var,
this_function_var, pos);
return new (local_zone_) SuperCallReference(
local_zone_, this_var, new_target_var, this_function_var, pos);
}
EmptyParentheses* NewEmptyParentheses(int pos) {
return new (zone_) EmptyParentheses(zone_, pos);
return new (local_zone_) EmptyParentheses(local_zone_, pos);
}
Zone* zone() const { return zone_; }
void set_zone(Zone* zone) { zone_ = zone; }
Zone* zone() const { return local_zone_; }
// Handles use of temporary zones when parsing inner function bodies.
class BodyScope {
public:
BodyScope(AstNodeFactory* factory, Zone* temp_zone, bool use_temp_zone)
: factory_(factory), prev_zone_(factory->zone_) {
: factory_(factory), prev_zone_(factory->local_zone_) {
if (use_temp_zone) {
factory->zone_ = temp_zone;
factory->local_zone_ = temp_zone;
}
}
~BodyScope() { factory_->zone_ = prev_zone_; }
~BodyScope() { factory_->local_zone_ = prev_zone_; }
private:
AstNodeFactory* factory_;
......@@ -3477,7 +3493,10 @@ class AstNodeFactory final BASE_EMBEDDED {
// which we can guarantee is not going to be compiled or have its AST
// inspected.
// See ParseFunctionLiteral in parser.cc for preconditions.
Zone* zone_;
Zone* local_zone_;
// ZoneObjects which need to persist until scope analysis must be allocated in
// the parser-level zone.
Zone* parser_zone_;
AstValueFactory* ast_value_factory_;
};
......
......@@ -279,7 +279,6 @@ bool Scope::Analyze(ParseInfo* info) {
scope->Print();
}
scope->CheckScopePositions();
scope->CheckZones();
#endif
info->set_scope(scope);
......@@ -503,11 +502,9 @@ Variable* Scope::LookupFunctionVar(const AstRawString* name,
if (index < 0) return NULL;
Variable* var = new (zone())
Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized);
DCHECK_NOT_NULL(factory);
VariableProxy* proxy = factory->NewVariableProxy(var);
VariableDeclaration* declaration =
factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition);
DCHECK_EQ(factory->zone(), zone());
DeclareFunctionVar(declaration);
var->AllocateTo(VariableLocation::CONTEXT, index);
return var;
......@@ -892,41 +889,6 @@ Handle<StringSet> Scope::CollectNonLocals(Handle<StringSet> non_locals) {
return non_locals;
}
void Scope::AnalyzePartially(Scope* migrate_to,
AstNodeFactory* ast_node_factory) {
// Gather info from inner scopes.
PropagateScopeInfo(false);
// Try to resolve unresolved variables for this Scope and collect those which
// cannot be resolved inside. It doesn't make sense to try to resolve them in
// the outer Scopes here, because they are incomplete.
VariableProxy* still_unresolved = nullptr;
CollectUnresolvableLocals(&still_unresolved, this);
// Re-create the VariableProxies in the right Zone and insert them into
// migrate_to.
for (VariableProxy* proxy = still_unresolved; proxy != nullptr;
proxy = proxy->next_unresolved()) {
// Recreate the VariableProxy.
DCHECK(!proxy->is_resolved());
VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
migrate_to->AddUnresolved(copy);
}
// Push scope data up to migrate_to. Note that migrate_to and this Scope
// describe the same Scope, just in different Zones.
PropagateUsageFlagsToScope(migrate_to);
if (inner_scope_calls_eval_) {
migrate_to->inner_scope_calls_eval_ = true;
}
DCHECK(!force_eager_compilation_);
migrate_to->set_start_position(start_position_);
migrate_to->set_end_position(end_position_);
migrate_to->language_mode_ = language_mode_;
outer_scope_->RemoveInnerScope(this);
DCHECK_EQ(outer_scope_, migrate_to->outer_scope_);
DCHECK_EQ(outer_scope_->zone(), migrate_to->zone());
}
#ifdef DEBUG
static const char* Header(ScopeType scope_type, FunctionKind function_kind,
......@@ -1135,12 +1097,6 @@ void Scope::CheckScopePositions() {
scope->CheckScopePositions();
}
}
void Scope::CheckZones() {
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
CHECK_EQ(scope->zone(), zone());
}
}
#endif // DEBUG
......@@ -1163,10 +1119,10 @@ Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
return var;
}
Variable* Scope::LookupRecursive(VariableProxy* proxy,
BindingKind* binding_kind,
AstNodeFactory* factory,
Scope* max_outer_scope) {
AstNodeFactory* factory) {
DCHECK(binding_kind != NULL);
if (already_resolved() && is_with_scope()) {
// Short-cut: if the scope is deserialized from a scope info, variable
......@@ -1193,14 +1149,13 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy,
var = LookupFunctionVar(proxy->raw_name(), factory);
if (var != NULL) {
*binding_kind = BOUND;
} else if (outer_scope_ != nullptr && this != max_outer_scope) {
var = outer_scope_->LookupRecursive(proxy, binding_kind, factory,
max_outer_scope);
} else if (outer_scope_ != NULL) {
var = outer_scope_->LookupRecursive(proxy, binding_kind, factory);
if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
var->ForceContextAllocation();
}
} else {
DCHECK(is_script_scope() || this == max_outer_scope);
DCHECK(is_script_scope());
}
// "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes.
......@@ -1333,26 +1288,6 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info,
return true;
}
void Scope::CollectUnresolvableLocals(VariableProxy** still_unresolved,
Scope* max_outer_scope) {
BindingKind binding_kind;
for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr;
proxy = next) {
next = proxy->next_unresolved();
// Note that we pass nullptr as AstNodeFactory: this phase should not create
// any new AstNodes, since none of the Scopes involved are backed up by
// ScopeInfo.
if (LookupRecursive(proxy, &binding_kind, nullptr, max_outer_scope) ==
nullptr) {
proxy->set_next_unresolved(*still_unresolved);
*still_unresolved = proxy;
}
}
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
scope->CollectUnresolvableLocals(still_unresolved, max_outer_scope);
}
}
void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) {
if (outer_scope_calls_sloppy_eval) {
......
......@@ -201,7 +201,6 @@ class Scope: public ZoneObject {
// the same name because they may be removed selectively via
// RemoveUnresolved().
DCHECK(!already_resolved());
DCHECK_EQ(factory->zone(), zone());
VariableProxy* proxy =
factory->NewVariableProxy(name, kind, start_position, end_position);
proxy->set_next_unresolved(unresolved_);
......@@ -610,13 +609,6 @@ class Scope: public ZoneObject {
return &sloppy_block_function_map_;
}
// To be called during parsing. Do just enough scope analysis that we can
// discard the Scope for lazily compiled functions. In particular, this
// records variables which cannot be resolved inside the Scope (we don't yet
// know what they will resolve to since the outer Scopes are incomplete) and
// migrates them into migrate_to.
void AnalyzePartially(Scope* migrate_to, AstNodeFactory* ast_node_factory);
// ---------------------------------------------------------------------------
// Debugging.
......@@ -625,9 +617,6 @@ class Scope: public ZoneObject {
// Check that the scope has positions assigned.
void CheckScopePositions();
// Check that all Scopes in the scope tree use the same Zone.
void CheckZones();
#endif
// ---------------------------------------------------------------------------
......@@ -788,23 +777,16 @@ class Scope: public ZoneObject {
};
// Lookup a variable reference given by name recursively starting with this
// scope, but only until max_outer_scope (if not nullptr). If the code is
// executed because of a call to 'eval', the context parameter should be set
// to the calling context of 'eval'.
// scope. If the code is executed because of a call to 'eval', the context
// parameter should be set to the calling context of 'eval'.
Variable* LookupRecursive(VariableProxy* proxy, BindingKind* binding_kind,
AstNodeFactory* factory,
Scope* max_outer_scope = nullptr);
AstNodeFactory* factory);
MUST_USE_RESULT
bool ResolveVariable(ParseInfo* info, VariableProxy* proxy,
AstNodeFactory* factory);
MUST_USE_RESULT
bool ResolveVariablesRecursively(ParseInfo* info, AstNodeFactory* factory);
// Tries to resolve local variables inside max_outer_scope; collects those
// which cannot be resolved.
void CollectUnresolvableLocals(VariableProxy** still_unresolved,
Scope* max_outer_scope);
// Scope analysis.
void PropagateScopeInfo(bool outer_scope_calls_sloppy_eval);
bool HasTrivialContext() const;
......
......@@ -464,11 +464,7 @@ class ParserBase : public Traits {
return &non_patterns_to_rewrite_;
}
bool next_function_is_parenthesized() const {
return next_function_is_parenthesized_;
}
void set_next_function_is_parenthesized(bool parenthesized) {
void next_function_is_parenthesized(bool parenthesized) {
next_function_is_parenthesized_ = parenthesized;
}
......@@ -1241,8 +1237,6 @@ class ParserBase : public Traits {
bool allow_harmony_async_await_;
bool allow_harmony_restrictive_generators_;
bool allow_harmony_trailing_commas_;
friend class DiscardableZoneScope;
};
template <class Traits>
......@@ -1636,7 +1630,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
}
// Heuristically try to detect immediately called functions before
// seeing the call parentheses.
function_state_->set_next_function_is_parenthesized(peek() ==
function_state_->next_function_is_parenthesized(peek() ==
Token::FUNCTION);
ExpressionT expr = this->ParseExpression(true, classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
......
......@@ -176,26 +176,18 @@ class DiscardableZoneScope {
: ast_node_factory_scope_(parser->factory(), temp_zone, use_temp_zone),
fni_(parser->ast_value_factory_, temp_zone),
parser_(parser),
prev_fni_(parser->fni_),
prev_zone_(parser->zone_) {
prev_fni_(parser->fni_) {
if (use_temp_zone) {
parser_->fni_ = &fni_;
parser_->zone_ = temp_zone;
}
}
~DiscardableZoneScope() {
parser_->fni_ = prev_fni_;
parser_->zone_ = prev_zone_;
}
~DiscardableZoneScope() { parser_->fni_ = prev_fni_; }
private:
AstNodeFactory::BodyScope ast_node_factory_scope_;
FuncNameInferrer fni_;
Parser* parser_;
FuncNameInferrer* prev_fni_;
Zone* prev_zone_;
DISALLOW_COPY_AND_ASSIGN(DiscardableZoneScope);
};
void Parser::SetCachedData(ParseInfo* info) {
......@@ -4290,113 +4282,29 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
function_name = ast_value_factory()->empty_string();
}
FunctionLiteral::EagerCompileHint eager_compile_hint =
function_state_->next_function_is_parenthesized()
? FunctionLiteral::kShouldEagerCompile
: FunctionLiteral::kShouldLazyCompile;
// Determine if the function can be parsed lazily. Lazy parsing is
// different from lazy compilation; we need to parse more eagerly than we
// compile.
// We can only parse lazily if we also compile lazily. The heuristics for lazy
// compilation are:
// - It must not have been prohibited by the caller to Parse (some callers
// need a full AST).
// - The outer scope must allow lazy compilation of inner functions.
// - The function mustn't be a function expression with an open parenthesis
// before; we consider that a hint that the function will be called
// immediately, and it would be a waste of time to make it lazily
// compiled.
// These are all things we can know at this point, without looking at the
// function itself.
// In addition, we need to distinguish between these cases:
// (function foo() {
// bar = function() { return 1; }
// })();
// and
// (function foo() {
// var a = 1;
// bar = function() { return a; }
// })();
// Now foo will be parsed eagerly and compiled eagerly (optimization: assume
// parenthesis before the function means that it will be called
// immediately). The inner function *must* be parsed eagerly to resolve the
// possible reference to the variable in foo's scope. However, it's possible
// that it will be compiled lazily.
// To make this additional case work, both Parser and PreParser implement a
// logic where only top-level functions will be parsed lazily.
bool is_lazily_parsed = mode() == PARSE_LAZILY &&
this->scope()->AllowsLazyParsing() &&
!function_state_->next_function_is_parenthesized();
// Determine whether the function body can be discarded after parsing.
// The preconditions are:
// - Lazy compilation has to be enabled.
// - Neither V8 natives nor native function declarations can be allowed,
// since parsing one would retroactively force the function to be
// eagerly compiled.
// - The invoker of this parser can't depend on the AST being eagerly
// built (either because the function is about to be compiled, or
// because the AST is going to be inspected for some reason).
// - Because of the above, we can't be attempting to parse a
// FunctionExpression; even without enclosing parentheses it might be
// immediately invoked.
// - The function literal shouldn't be hinted to eagerly compile.
// - For asm.js functions the body needs to be available when module
// validation is active, because we examine the entire module at once.
bool use_temp_zone =
!is_lazily_parsed && FLAG_lazy && !allow_natives() &&
extension_ == NULL && allow_lazy() &&
function_type == FunctionLiteral::kDeclaration &&
eager_compile_hint != FunctionLiteral::kShouldEagerCompile &&
!(FLAG_validate_asm && scope()->asm_module());
Scope* main_scope = nullptr;
if (use_temp_zone) {
// This Scope lives in the main Zone; we'll migrate data into it later.
main_scope = NewFunctionScope(kind);
}
ZoneList<Statement*>* body = nullptr;
Scope* scope = NewFunctionScope(kind);
SetLanguageMode(scope, language_mode);
ZoneList<Statement*>* body = NULL;
int arity = -1;
int materialized_literal_count = -1;
int expected_property_count = -1;
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
bool should_be_used_once_hint = false;
bool has_duplicate_parameters;
FunctionLiteral::EagerCompileHint eager_compile_hint;
// Parse function.
{
// Temporary zones can nest. When we migrate free variables (see below), we
// need to recreate them in the previous Zone.
AstNodeFactory previous_zone_ast_node_factory(ast_value_factory());
previous_zone_ast_node_factory.set_zone(zone());
// Open a new zone scope, which sets our AstNodeFactory to allocate in the
// new temporary zone if the preconditions are satisfied, and ensures that
// the previous zone is always restored after parsing the body. To be able
// to do scope analysis correctly after full parsing, we migrate needed
// information from scope into main_scope when the function has been parsed.
Zone temp_zone(zone()->allocator());
DiscardableZoneScope zone_scope(this, &temp_zone, use_temp_zone);
Scope* scope = NewFunctionScope(kind);
SetLanguageMode(scope, language_mode);
if (!use_temp_zone) {
main_scope = scope;
} else {
DCHECK(main_scope->zone() != scope->zone());
}
FunctionState function_state(&function_state_, &scope_state_, scope, kind);
#ifdef DEBUG
this->scope()->SetScopeName(function_name);
#endif
ExpressionClassifier formals_classifier(this, &duplicate_finder);
eager_compile_hint = function_state_->this_function_is_parenthesized()
? FunctionLiteral::kShouldEagerCompile
: FunctionLiteral::kShouldLazyCompile;
if (is_generator) {
// For generators, allocating variables in contexts is currently a win
// because it minimizes the work needed to suspend and resume an
......@@ -4429,6 +4337,43 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// which says whether we need to create an arguments adaptor frame).
if (formals.has_rest) arity--;
// Determine if the function can be parsed lazily. Lazy parsing is different
// from lazy compilation; we need to parse more eagerly than we compile.
// We can only parse lazily if we also compile lazily. The heuristics for
// lazy compilation are:
// - It must not have been prohibited by the caller to Parse (some callers
// need a full AST).
// - The outer scope must allow lazy compilation of inner functions.
// - The function mustn't be a function expression with an open parenthesis
// before; we consider that a hint that the function will be called
// immediately, and it would be a waste of time to make it lazily
// compiled.
// These are all things we can know at this point, without looking at the
// function itself.
// In addition, we need to distinguish between these cases:
// (function foo() {
// bar = function() { return 1; }
// })();
// and
// (function foo() {
// var a = 1;
// bar = function() { return a; }
// })();
// Now foo will be parsed eagerly and compiled eagerly (optimization: assume
// parenthesis before the function means that it will be called
// immediately). The inner function *must* be parsed eagerly to resolve the
// possible reference to the variable in foo's scope. However, it's possible
// that it will be compiled lazily.
// To make this additional case work, both Parser and PreParser implement a
// logic where only top-level functions will be parsed lazily.
bool is_lazily_parsed = mode() == PARSE_LAZILY &&
this->scope()->AllowsLazyParsing() &&
!function_state_->this_function_is_parenthesized();
// Eager or lazy parse?
// If is_lazily_parsed, we'll parse lazy. If we can set a bookmark, we'll
// pass it to SkipLazyFunctionBody, which may use it to abort lazy
......@@ -4457,15 +4402,45 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
}
}
if (!is_lazily_parsed) {
// Determine whether the function body can be discarded after parsing.
// The preconditions are:
// - Lazy compilation has to be enabled.
// - Neither V8 natives nor native function declarations can be allowed,
// since parsing one would retroactively force the function to be
// eagerly compiled.
// - The invoker of this parser can't depend on the AST being eagerly
// built (either because the function is about to be compiled, or
// because the AST is going to be inspected for some reason).
// - Because of the above, we can't be attempting to parse a
// FunctionExpression; even without enclosing parentheses it might be
// immediately invoked.
// - The function literal shouldn't be hinted to eagerly compile.
// - For asm.js functions the body needs to be available when module
// validation is active, because we examine the entire module at once.
bool use_temp_zone =
FLAG_lazy && !allow_natives() && extension_ == NULL && allow_lazy() &&
function_type == FunctionLiteral::kDeclaration &&
eager_compile_hint != FunctionLiteral::kShouldEagerCompile &&
!(FLAG_validate_asm && scope->asm_function());
// Open a new zone scope, which sets our AstNodeFactory to allocate in the
// new temporary zone if the preconditions are satisfied, and ensures that
// the previous zone is always restored after parsing the body.
// For the purpose of scope analysis, some ZoneObjects allocated by the
// factory must persist after the function body is thrown away and
// temp_zone is deallocated. These objects are instead allocated in a
// parser-persistent zone (see parser_zone_ in AstNodeFactory).
{
Zone temp_zone(zone()->allocator());
DiscardableZoneScope zone_scope(this, &temp_zone, use_temp_zone);
body = ParseEagerFunctionBody(function_name, pos, formals, kind,
function_type, CHECK_OK);
}
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
if (use_temp_zone) {
// If the preconditions are correct the function body should never be
// accessed, but do this anyway for better behaviour if they're wrong.
body = nullptr;
body = NULL;
}
}
......@@ -4495,20 +4470,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
}
has_duplicate_parameters =
!formals_classifier.is_valid_formal_parameter_list_without_duplicates();
if (use_temp_zone) {
DCHECK(main_scope != scope);
scope->AnalyzePartially(main_scope, &previous_zone_ast_node_factory);
}
} // DiscardableZoneScope goes out of scope.
FunctionLiteral::ParameterFlag duplicate_parameters =
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
: FunctionLiteral::kNoDuplicateParameters;
// Note that the FunctionLiteral needs to be created in the main Zone again.
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
function_name, main_scope, body, materialized_literal_count,
function_name, scope, body, materialized_literal_count,
expected_property_count, arity, duplicate_parameters, function_type,
eager_compile_hint, kind, pos);
function_literal->set_function_token_position(function_token_pos);
......
......@@ -724,6 +724,7 @@ class Parser : public ParserBase<ParserTraits> {
private:
friend class ParserTraits;
friend class DiscardableZoneScope;
// Runtime encoding of different completion modes.
enum CompletionKind {
......
......@@ -35,19 +35,3 @@ function foo() {
}
assertEquals("hello world", foo());
// Also test that it works from more deeply nested inner functions:
var v = (function foo2() {
var a, b;
var bar = function() {
var baz = function() {
a = b = "bye world";
}
baz();
}
bar();
return a;
})();
assertEquals("bye world", v);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment