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, ...@@ -204,18 +204,6 @@ VariableProxy::VariableProxy(Zone* zone, const AstRawString* name,
raw_name_(name), raw_name_(name),
next_unresolved_(nullptr) {} 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) { void VariableProxy::BindTo(Variable* var) {
DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name()); DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name());
set_var(var); set_var(var);
......
...@@ -1690,7 +1690,6 @@ class VariableProxy final : public Expression { ...@@ -1690,7 +1690,6 @@ class VariableProxy final : public Expression {
VariableProxy(Zone* zone, const AstRawString* name, VariableProxy(Zone* zone, const AstRawString* name,
Variable::Kind variable_kind, int start_position, Variable::Kind variable_kind, int start_position,
int end_position); int end_position);
VariableProxy(Zone* zone, const VariableProxy* copy_from);
static int parent_num_ids() { return Expression::num_ids(); } static int parent_num_ids() { return Expression::num_ids(); }
int local_id(int n) const { return base_id() + parent_num_ids() + n; } int local_id(int n) const { return base_id() + parent_num_ids() + n; }
...@@ -3044,22 +3043,27 @@ class AstVisitor BASE_EMBEDDED { ...@@ -3044,22 +3043,27 @@ class AstVisitor BASE_EMBEDDED {
class AstNodeFactory final BASE_EMBEDDED { class AstNodeFactory final BASE_EMBEDDED {
public: public:
explicit AstNodeFactory(AstValueFactory* ast_value_factory) 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) { 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_; } AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
void set_ast_value_factory(AstValueFactory* ast_value_factory) { void set_ast_value_factory(AstValueFactory* ast_value_factory) {
ast_value_factory_ = 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, VariableDeclaration* NewVariableDeclaration(VariableProxy* proxy,
VariableMode mode, Scope* scope, VariableMode mode, Scope* scope,
int pos) { 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, FunctionDeclaration* NewFunctionDeclaration(VariableProxy* proxy,
...@@ -3067,18 +3071,19 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3067,18 +3071,19 @@ class AstNodeFactory final BASE_EMBEDDED {
FunctionLiteral* fun, FunctionLiteral* fun,
Scope* scope, Scope* scope,
int pos) { 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, Block* NewBlock(ZoneList<const AstRawString*>* labels, int capacity,
bool ignore_completion_value, int pos) { bool ignore_completion_value, int pos) {
return new (zone_) return new (local_zone_)
Block(zone_, labels, capacity, ignore_completion_value, pos); Block(local_zone_, labels, capacity, ignore_completion_value, pos);
} }
#define STATEMENT_WITH_LABELS(NodeType) \ #define STATEMENT_WITH_LABELS(NodeType) \
NodeType* New##NodeType(ZoneList<const AstRawString*>* labels, int pos) { \ 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(DoWhileStatement)
STATEMENT_WITH_LABELS(WhileStatement) STATEMENT_WITH_LABELS(WhileStatement)
...@@ -3091,10 +3096,10 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3091,10 +3096,10 @@ class AstNodeFactory final BASE_EMBEDDED {
int pos) { int pos) {
switch (visit_mode) { switch (visit_mode) {
case ForEachStatement::ENUMERATE: { case ForEachStatement::ENUMERATE: {
return new (zone_) ForInStatement(zone_, labels, pos); return new (local_zone_) ForInStatement(local_zone_, labels, pos);
} }
case ForEachStatement::ITERATE: { case ForEachStatement::ITERATE: {
return new (zone_) ForOfStatement(zone_, labels, pos); return new (local_zone_) ForOfStatement(local_zone_, labels, pos);
} }
} }
UNREACHABLE(); UNREACHABLE();
...@@ -3102,41 +3107,42 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3102,41 +3107,42 @@ class AstNodeFactory final BASE_EMBEDDED {
} }
ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) { 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) { 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) { 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) { 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, WithStatement* NewWithStatement(Scope* scope,
Expression* expression, Expression* expression,
Statement* statement, Statement* statement,
int pos) { 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, IfStatement* NewIfStatement(Expression* condition,
Statement* then_statement, Statement* then_statement,
Statement* else_statement, Statement* else_statement,
int pos) { int pos) {
return new (zone_) return new (local_zone_) IfStatement(local_zone_, condition, then_statement,
IfStatement(zone_, condition, then_statement, else_statement, pos); else_statement, pos);
} }
TryCatchStatement* NewTryCatchStatement(Block* try_block, Scope* scope, TryCatchStatement* NewTryCatchStatement(Block* try_block, Scope* scope,
Variable* variable, Variable* variable,
Block* catch_block, int pos) { Block* catch_block, int pos) {
return new (zone_) return new (local_zone_)
TryCatchStatement(zone_, try_block, scope, variable, catch_block, TryCatchStatement(local_zone_, try_block, scope, variable, catch_block,
HandlerTable::CAUGHT, pos); HandlerTable::CAUGHT, pos);
} }
...@@ -3145,8 +3151,8 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3145,8 +3151,8 @@ class AstNodeFactory final BASE_EMBEDDED {
Variable* variable, Variable* variable,
Block* catch_block, Block* catch_block,
int pos) { int pos) {
return new (zone_) return new (local_zone_)
TryCatchStatement(zone_, try_block, scope, variable, catch_block, TryCatchStatement(local_zone_, try_block, scope, variable, catch_block,
HandlerTable::UNCAUGHT, pos); HandlerTable::UNCAUGHT, pos);
} }
...@@ -3155,81 +3161,88 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3155,81 +3161,88 @@ class AstNodeFactory final BASE_EMBEDDED {
Variable* variable, Variable* variable,
Block* catch_block, Block* catch_block,
int pos) { int pos) {
return new (zone_) return new (local_zone_)
TryCatchStatement(zone_, try_block, scope, variable, catch_block, TryCatchStatement(local_zone_, try_block, scope, variable, catch_block,
HandlerTable::PROMISE, pos); HandlerTable::PROMISE, pos);
} }
TryFinallyStatement* NewTryFinallyStatement(Block* try_block, TryFinallyStatement* NewTryFinallyStatement(Block* try_block,
Block* finally_block, int pos) { Block* finally_block, int pos) {
return new (zone_) return new (local_zone_)
TryFinallyStatement(zone_, try_block, finally_block, pos); TryFinallyStatement(local_zone_, try_block, finally_block, pos);
} }
DebuggerStatement* NewDebuggerStatement(int pos) { DebuggerStatement* NewDebuggerStatement(int pos) {
return new (zone_) DebuggerStatement(zone_, pos); return new (local_zone_) DebuggerStatement(local_zone_, pos);
} }
EmptyStatement* NewEmptyStatement(int pos) { EmptyStatement* NewEmptyStatement(int pos) {
return new (zone_) EmptyStatement(zone_, pos); return new (local_zone_) EmptyStatement(local_zone_, pos);
} }
SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement( SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(
Statement* statement, Scope* scope) { Statement* statement, Scope* scope) {
return new (zone_) SloppyBlockFunctionStatement(zone_, statement, scope); return new (parser_zone_)
SloppyBlockFunctionStatement(parser_zone_, statement, scope);
} }
CaseClause* NewCaseClause( CaseClause* NewCaseClause(
Expression* label, ZoneList<Statement*>* statements, int pos) { 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) { Literal* NewStringLiteral(const AstRawString* string, int pos) {
return new (zone_) return new (local_zone_)
Literal(zone_, ast_value_factory_->NewString(string), pos); Literal(local_zone_, ast_value_factory_->NewString(string), pos);
} }
// A JavaScript symbol (ECMA-262 edition 6). // A JavaScript symbol (ECMA-262 edition 6).
Literal* NewSymbolLiteral(const char* name, int pos) { 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) { Literal* NewNumberLiteral(double number, int pos, bool with_dot = false) {
return new (zone_) return new (local_zone_) Literal(
Literal(zone_, ast_value_factory_->NewNumber(number, with_dot), pos); local_zone_, ast_value_factory_->NewNumber(number, with_dot), pos);
} }
Literal* NewSmiLiteral(int number, int 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) { 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) { 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) { 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) { 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( ObjectLiteral* NewObjectLiteral(
ZoneList<ObjectLiteral::Property*>* properties, int literal_index, ZoneList<ObjectLiteral::Property*>* properties, int literal_index,
uint32_t boilerplate_properties, int pos) { uint32_t boilerplate_properties, int pos) {
return new (zone_) ObjectLiteral(zone_, properties, literal_index, return new (local_zone_) ObjectLiteral(
boilerplate_properties, pos); local_zone_, properties, literal_index, boilerplate_properties, pos);
} }
ObjectLiteral::Property* NewObjectLiteralProperty( ObjectLiteral::Property* NewObjectLiteralProperty(
Expression* key, Expression* value, ObjectLiteralProperty::Kind kind, Expression* key, Expression* value, ObjectLiteralProperty::Kind kind,
bool is_static, bool is_computed_name) { bool is_static, bool is_computed_name) {
return new (zone_) return new (local_zone_)
ObjectLiteral::Property(key, value, kind, is_static, is_computed_name); ObjectLiteral::Property(key, value, kind, is_static, is_computed_name);
} }
...@@ -3237,32 +3250,35 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3237,32 +3250,35 @@ class AstNodeFactory final BASE_EMBEDDED {
Expression* value, Expression* value,
bool is_static, bool is_static,
bool is_computed_name) { bool is_computed_name) {
return new (zone_) ObjectLiteral::Property(ast_value_factory_, key, value, return new (local_zone_) ObjectLiteral::Property(
is_static, is_computed_name); ast_value_factory_, key, value, is_static, is_computed_name);
} }
RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern, int flags, RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern, int flags,
int literal_index, int pos) { 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, ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
int literal_index, int literal_index,
int pos) { 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, ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
int first_spread_index, int literal_index, int first_spread_index, int literal_index,
int pos) { int pos) {
return new (zone_) return new (local_zone_) ArrayLiteral(
ArrayLiteral(zone_, values, first_spread_index, literal_index, pos); local_zone_, values, first_spread_index, literal_index, pos);
} }
VariableProxy* NewVariableProxy(Variable* var, VariableProxy* NewVariableProxy(Variable* var,
int start_position = kNoSourcePosition, int start_position = kNoSourcePosition,
int end_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, VariableProxy* NewVariableProxy(const AstRawString* name,
...@@ -3270,89 +3286,87 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3270,89 +3286,87 @@ class AstNodeFactory final BASE_EMBEDDED {
int start_position = kNoSourcePosition, int start_position = kNoSourcePosition,
int end_position = kNoSourcePosition) { int end_position = kNoSourcePosition) {
DCHECK_NOT_NULL(name); DCHECK_NOT_NULL(name);
return new (zone_) return new (parser_zone_) VariableProxy(parser_zone_, name, variable_kind,
VariableProxy(zone_, name, variable_kind, start_position, end_position); start_position, end_position);
}
// Recreates the VariableProxy in this Zone.
VariableProxy* CopyVariableProxy(VariableProxy* proxy) {
return new (zone_) VariableProxy(zone_, proxy);
} }
Property* NewProperty(Expression* obj, Expression* key, int pos) { 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, Call* NewCall(Expression* expression,
ZoneList<Expression*>* arguments, ZoneList<Expression*>* arguments,
int pos) { int pos) {
return new (zone_) Call(zone_, expression, arguments, pos); return new (local_zone_) Call(local_zone_, expression, arguments, pos);
} }
CallNew* NewCallNew(Expression* expression, CallNew* NewCallNew(Expression* expression,
ZoneList<Expression*>* arguments, ZoneList<Expression*>* arguments,
int pos) { 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, CallRuntime* NewCallRuntime(Runtime::FunctionId id,
ZoneList<Expression*>* arguments, int pos) { ZoneList<Expression*>* arguments, int pos) {
return new (zone_) return new (local_zone_)
CallRuntime(zone_, Runtime::FunctionForId(id), arguments, pos); CallRuntime(local_zone_, Runtime::FunctionForId(id), arguments, pos);
} }
CallRuntime* NewCallRuntime(const Runtime::Function* function, CallRuntime* NewCallRuntime(const Runtime::Function* function,
ZoneList<Expression*>* arguments, int pos) { 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, CallRuntime* NewCallRuntime(int context_index,
ZoneList<Expression*>* arguments, int pos) { 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, UnaryOperation* NewUnaryOperation(Token::Value op,
Expression* expression, Expression* expression,
int pos) { 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, BinaryOperation* NewBinaryOperation(Token::Value op,
Expression* left, Expression* left,
Expression* right, Expression* right,
int pos) { 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, CountOperation* NewCountOperation(Token::Value op,
bool is_prefix, bool is_prefix,
Expression* expr, Expression* expr,
int pos) { 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, CompareOperation* NewCompareOperation(Token::Value op,
Expression* left, Expression* left,
Expression* right, Expression* right,
int pos) { 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) { 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, Conditional* NewConditional(Expression* condition,
Expression* then_expression, Expression* then_expression,
Expression* else_expression, Expression* else_expression,
int position) { int position) {
return new (zone_) Conditional(zone_, condition, then_expression, return new (local_zone_) Conditional(
else_expression, position); local_zone_, condition, then_expression, else_expression, position);
} }
RewritableExpression* NewRewritableExpression(Expression* expression) { RewritableExpression* NewRewritableExpression(Expression* expression) {
DCHECK_NOT_NULL(expression); DCHECK_NOT_NULL(expression);
return new (zone_) RewritableExpression(zone_, expression); return new (local_zone_) RewritableExpression(local_zone_, expression);
} }
Assignment* NewAssignment(Token::Value op, Assignment* NewAssignment(Token::Value op,
...@@ -3360,7 +3374,8 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3360,7 +3374,8 @@ class AstNodeFactory final BASE_EMBEDDED {
Expression* value, Expression* value,
int pos) { int pos) {
DCHECK(Token::IsAssignmentOp(op)); 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()) { if (assign->is_compound()) {
DCHECK(Token::IsAssignmentOp(op)); DCHECK(Token::IsAssignmentOp(op));
assign->binary_operation_ = assign->binary_operation_ =
...@@ -3372,12 +3387,12 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3372,12 +3387,12 @@ class AstNodeFactory final BASE_EMBEDDED {
Yield* NewYield(Expression* generator_object, Expression* expression, int pos, Yield* NewYield(Expression* generator_object, Expression* expression, int pos,
Yield::OnException on_exception) { Yield::OnException on_exception) {
if (!expression) expression = NewUndefinedLiteral(pos); if (!expression) expression = NewUndefinedLiteral(pos);
return new (zone_) return new (local_zone_)
Yield(zone_, generator_object, expression, pos, on_exception); Yield(local_zone_, generator_object, expression, pos, on_exception);
} }
Throw* NewThrow(Expression* exception, int pos) { Throw* NewThrow(Expression* exception, int pos) {
return new (zone_) Throw(zone_, exception, pos); return new (local_zone_) Throw(local_zone_, exception, pos);
} }
FunctionLiteral* NewFunctionLiteral( FunctionLiteral* NewFunctionLiteral(
...@@ -3388,8 +3403,8 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3388,8 +3403,8 @@ class AstNodeFactory final BASE_EMBEDDED {
FunctionLiteral::FunctionType function_type, FunctionLiteral::FunctionType function_type,
FunctionLiteral::EagerCompileHint eager_compile_hint, FunctionKind kind, FunctionLiteral::EagerCompileHint eager_compile_hint, FunctionKind kind,
int position) { int position) {
return new (zone_) FunctionLiteral( return new (local_zone_) FunctionLiteral(
zone_, name, ast_value_factory_, scope, body, local_zone_, name, ast_value_factory_, scope, body,
materialized_literal_count, expected_property_count, parameter_count, materialized_literal_count, expected_property_count, parameter_count,
function_type, has_duplicate_parameters, eager_compile_hint, kind, function_type, has_duplicate_parameters, eager_compile_hint, kind,
position, true); position, true);
...@@ -3401,9 +3416,9 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3401,9 +3416,9 @@ class AstNodeFactory final BASE_EMBEDDED {
FunctionLiteral* NewScriptOrEvalFunctionLiteral( FunctionLiteral* NewScriptOrEvalFunctionLiteral(
Scope* scope, ZoneList<Statement*>* body, int materialized_literal_count, Scope* scope, ZoneList<Statement*>* body, int materialized_literal_count,
int expected_property_count) { int expected_property_count) {
return new (zone_) FunctionLiteral( return new (local_zone_) FunctionLiteral(
zone_, ast_value_factory_->empty_string(), ast_value_factory_, scope, local_zone_, ast_value_factory_->empty_string(), ast_value_factory_,
body, materialized_literal_count, expected_property_count, 0, scope, body, materialized_literal_count, expected_property_count, 0,
FunctionLiteral::kAnonymousExpression, FunctionLiteral::kAnonymousExpression,
FunctionLiteral::kNoDuplicateParameters, FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::kShouldLazyCompile, FunctionKind::kNormalFunction, 0, FunctionLiteral::kShouldLazyCompile, FunctionKind::kNormalFunction, 0,
...@@ -3414,58 +3429,59 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3414,58 +3429,59 @@ class AstNodeFactory final BASE_EMBEDDED {
FunctionLiteral* constructor, FunctionLiteral* constructor,
ZoneList<ObjectLiteral::Property*>* properties, ZoneList<ObjectLiteral::Property*>* properties,
int start_position, int end_position) { int start_position, int end_position) {
return new (zone_) ClassLiteral(zone_, proxy, extends, constructor, return new (local_zone_)
properties, start_position, end_position); ClassLiteral(local_zone_, proxy, extends, constructor, properties,
start_position, end_position);
} }
NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name, NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name,
v8::Extension* extension, v8::Extension* extension,
int pos) { 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) { DoExpression* NewDoExpression(Block* block, Variable* result_var, int pos) {
VariableProxy* result = NewVariableProxy(result_var, 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) { ThisFunction* NewThisFunction(int pos) {
return new (zone_) ThisFunction(zone_, pos); return new (local_zone_) ThisFunction(local_zone_, pos);
} }
SuperPropertyReference* NewSuperPropertyReference(VariableProxy* this_var, SuperPropertyReference* NewSuperPropertyReference(VariableProxy* this_var,
Expression* home_object, Expression* home_object,
int pos) { int pos) {
return new (zone_) return new (local_zone_)
SuperPropertyReference(zone_, this_var, home_object, pos); SuperPropertyReference(local_zone_, this_var, home_object, pos);
} }
SuperCallReference* NewSuperCallReference(VariableProxy* this_var, SuperCallReference* NewSuperCallReference(VariableProxy* this_var,
VariableProxy* new_target_var, VariableProxy* new_target_var,
VariableProxy* this_function_var, VariableProxy* this_function_var,
int pos) { int pos) {
return new (zone_) SuperCallReference(zone_, this_var, new_target_var, return new (local_zone_) SuperCallReference(
this_function_var, pos); local_zone_, this_var, new_target_var, this_function_var, pos);
} }
EmptyParentheses* NewEmptyParentheses(int pos) { EmptyParentheses* NewEmptyParentheses(int pos) {
return new (zone_) EmptyParentheses(zone_, pos); return new (local_zone_) EmptyParentheses(local_zone_, pos);
} }
Zone* zone() const { return zone_; } Zone* zone() const { return local_zone_; }
void set_zone(Zone* zone) { zone_ = zone; }
// Handles use of temporary zones when parsing inner function bodies. // Handles use of temporary zones when parsing inner function bodies.
class BodyScope { class BodyScope {
public: public:
BodyScope(AstNodeFactory* factory, Zone* temp_zone, bool use_temp_zone) 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) { 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: private:
AstNodeFactory* factory_; AstNodeFactory* factory_;
...@@ -3477,7 +3493,10 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3477,7 +3493,10 @@ class AstNodeFactory final BASE_EMBEDDED {
// which we can guarantee is not going to be compiled or have its AST // which we can guarantee is not going to be compiled or have its AST
// inspected. // inspected.
// See ParseFunctionLiteral in parser.cc for preconditions. // 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_; AstValueFactory* ast_value_factory_;
}; };
......
...@@ -279,7 +279,6 @@ bool Scope::Analyze(ParseInfo* info) { ...@@ -279,7 +279,6 @@ bool Scope::Analyze(ParseInfo* info) {
scope->Print(); scope->Print();
} }
scope->CheckScopePositions(); scope->CheckScopePositions();
scope->CheckZones();
#endif #endif
info->set_scope(scope); info->set_scope(scope);
...@@ -503,11 +502,9 @@ Variable* Scope::LookupFunctionVar(const AstRawString* name, ...@@ -503,11 +502,9 @@ Variable* Scope::LookupFunctionVar(const AstRawString* name,
if (index < 0) return NULL; if (index < 0) return NULL;
Variable* var = new (zone()) Variable* var = new (zone())
Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized); Variable(this, name, mode, Variable::NORMAL, kCreatedInitialized);
DCHECK_NOT_NULL(factory);
VariableProxy* proxy = factory->NewVariableProxy(var); VariableProxy* proxy = factory->NewVariableProxy(var);
VariableDeclaration* declaration = VariableDeclaration* declaration =
factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition); factory->NewVariableDeclaration(proxy, mode, this, kNoSourcePosition);
DCHECK_EQ(factory->zone(), zone());
DeclareFunctionVar(declaration); DeclareFunctionVar(declaration);
var->AllocateTo(VariableLocation::CONTEXT, index); var->AllocateTo(VariableLocation::CONTEXT, index);
return var; return var;
...@@ -892,41 +889,6 @@ Handle<StringSet> Scope::CollectNonLocals(Handle<StringSet> non_locals) { ...@@ -892,41 +889,6 @@ Handle<StringSet> Scope::CollectNonLocals(Handle<StringSet> non_locals) {
return 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 #ifdef DEBUG
static const char* Header(ScopeType scope_type, FunctionKind function_kind, static const char* Header(ScopeType scope_type, FunctionKind function_kind,
...@@ -1135,12 +1097,6 @@ void Scope::CheckScopePositions() { ...@@ -1135,12 +1097,6 @@ void Scope::CheckScopePositions() {
scope->CheckScopePositions(); scope->CheckScopePositions();
} }
} }
void Scope::CheckZones() {
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
CHECK_EQ(scope->zone(), zone());
}
}
#endif // DEBUG #endif // DEBUG
...@@ -1163,10 +1119,10 @@ Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) { ...@@ -1163,10 +1119,10 @@ Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
return var; return var;
} }
Variable* Scope::LookupRecursive(VariableProxy* proxy, Variable* Scope::LookupRecursive(VariableProxy* proxy,
BindingKind* binding_kind, BindingKind* binding_kind,
AstNodeFactory* factory, AstNodeFactory* factory) {
Scope* max_outer_scope) {
DCHECK(binding_kind != NULL); DCHECK(binding_kind != NULL);
if (already_resolved() && is_with_scope()) { if (already_resolved() && is_with_scope()) {
// Short-cut: if the scope is deserialized from a scope info, variable // Short-cut: if the scope is deserialized from a scope info, variable
...@@ -1193,14 +1149,13 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy, ...@@ -1193,14 +1149,13 @@ Variable* Scope::LookupRecursive(VariableProxy* proxy,
var = LookupFunctionVar(proxy->raw_name(), factory); var = LookupFunctionVar(proxy->raw_name(), factory);
if (var != NULL) { if (var != NULL) {
*binding_kind = BOUND; *binding_kind = BOUND;
} else if (outer_scope_ != nullptr && this != max_outer_scope) { } else if (outer_scope_ != NULL) {
var = outer_scope_->LookupRecursive(proxy, binding_kind, factory, var = outer_scope_->LookupRecursive(proxy, binding_kind, factory);
max_outer_scope);
if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
var->ForceContextAllocation(); var->ForceContextAllocation();
} }
} else { } 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. // "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes.
...@@ -1333,26 +1288,6 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info, ...@@ -1333,26 +1288,6 @@ bool Scope::ResolveVariablesRecursively(ParseInfo* info,
return true; 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 ) { void Scope::PropagateScopeInfo(bool outer_scope_calls_sloppy_eval ) {
if (outer_scope_calls_sloppy_eval) { if (outer_scope_calls_sloppy_eval) {
......
...@@ -201,7 +201,6 @@ class Scope: public ZoneObject { ...@@ -201,7 +201,6 @@ class Scope: public ZoneObject {
// the same name because they may be removed selectively via // the same name because they may be removed selectively via
// RemoveUnresolved(). // RemoveUnresolved().
DCHECK(!already_resolved()); DCHECK(!already_resolved());
DCHECK_EQ(factory->zone(), zone());
VariableProxy* proxy = VariableProxy* proxy =
factory->NewVariableProxy(name, kind, start_position, end_position); factory->NewVariableProxy(name, kind, start_position, end_position);
proxy->set_next_unresolved(unresolved_); proxy->set_next_unresolved(unresolved_);
...@@ -610,13 +609,6 @@ class Scope: public ZoneObject { ...@@ -610,13 +609,6 @@ class Scope: public ZoneObject {
return &sloppy_block_function_map_; 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. // Debugging.
...@@ -625,9 +617,6 @@ class Scope: public ZoneObject { ...@@ -625,9 +617,6 @@ class Scope: public ZoneObject {
// Check that the scope has positions assigned. // Check that the scope has positions assigned.
void CheckScopePositions(); void CheckScopePositions();
// Check that all Scopes in the scope tree use the same Zone.
void CheckZones();
#endif #endif
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
...@@ -788,23 +777,16 @@ class Scope: public ZoneObject { ...@@ -788,23 +777,16 @@ class Scope: public ZoneObject {
}; };
// Lookup a variable reference given by name recursively starting with this // 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 // scope. If the code is executed because of a call to 'eval', the context
// executed because of a call to 'eval', the context parameter should be set // parameter should be set to the calling context of 'eval'.
// to the calling context of 'eval'.
Variable* LookupRecursive(VariableProxy* proxy, BindingKind* binding_kind, Variable* LookupRecursive(VariableProxy* proxy, BindingKind* binding_kind,
AstNodeFactory* factory, AstNodeFactory* factory);
Scope* max_outer_scope = nullptr);
MUST_USE_RESULT MUST_USE_RESULT
bool ResolveVariable(ParseInfo* info, VariableProxy* proxy, bool ResolveVariable(ParseInfo* info, VariableProxy* proxy,
AstNodeFactory* factory); AstNodeFactory* factory);
MUST_USE_RESULT MUST_USE_RESULT
bool ResolveVariablesRecursively(ParseInfo* info, AstNodeFactory* factory); 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. // Scope analysis.
void PropagateScopeInfo(bool outer_scope_calls_sloppy_eval); void PropagateScopeInfo(bool outer_scope_calls_sloppy_eval);
bool HasTrivialContext() const; bool HasTrivialContext() const;
......
...@@ -464,11 +464,7 @@ class ParserBase : public Traits { ...@@ -464,11 +464,7 @@ class ParserBase : public Traits {
return &non_patterns_to_rewrite_; return &non_patterns_to_rewrite_;
} }
bool next_function_is_parenthesized() const { void next_function_is_parenthesized(bool parenthesized) {
return next_function_is_parenthesized_;
}
void set_next_function_is_parenthesized(bool parenthesized) {
next_function_is_parenthesized_ = parenthesized; next_function_is_parenthesized_ = parenthesized;
} }
...@@ -1241,8 +1237,6 @@ class ParserBase : public Traits { ...@@ -1241,8 +1237,6 @@ class ParserBase : public Traits {
bool allow_harmony_async_await_; bool allow_harmony_async_await_;
bool allow_harmony_restrictive_generators_; bool allow_harmony_restrictive_generators_;
bool allow_harmony_trailing_commas_; bool allow_harmony_trailing_commas_;
friend class DiscardableZoneScope;
}; };
template <class Traits> template <class Traits>
...@@ -1636,7 +1630,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, ...@@ -1636,7 +1630,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
} }
// Heuristically try to detect immediately called functions before // Heuristically try to detect immediately called functions before
// seeing the call parentheses. // seeing the call parentheses.
function_state_->set_next_function_is_parenthesized(peek() == function_state_->next_function_is_parenthesized(peek() ==
Token::FUNCTION); Token::FUNCTION);
ExpressionT expr = this->ParseExpression(true, classifier, CHECK_OK); ExpressionT expr = this->ParseExpression(true, classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
......
...@@ -176,26 +176,18 @@ class DiscardableZoneScope { ...@@ -176,26 +176,18 @@ class DiscardableZoneScope {
: ast_node_factory_scope_(parser->factory(), temp_zone, use_temp_zone), : ast_node_factory_scope_(parser->factory(), temp_zone, use_temp_zone),
fni_(parser->ast_value_factory_, temp_zone), fni_(parser->ast_value_factory_, temp_zone),
parser_(parser), parser_(parser),
prev_fni_(parser->fni_), prev_fni_(parser->fni_) {
prev_zone_(parser->zone_) {
if (use_temp_zone) { if (use_temp_zone) {
parser_->fni_ = &fni_; parser_->fni_ = &fni_;
parser_->zone_ = temp_zone;
} }
} }
~DiscardableZoneScope() { ~DiscardableZoneScope() { parser_->fni_ = prev_fni_; }
parser_->fni_ = prev_fni_;
parser_->zone_ = prev_zone_;
}
private: private:
AstNodeFactory::BodyScope ast_node_factory_scope_; AstNodeFactory::BodyScope ast_node_factory_scope_;
FuncNameInferrer fni_; FuncNameInferrer fni_;
Parser* parser_; Parser* parser_;
FuncNameInferrer* prev_fni_; FuncNameInferrer* prev_fni_;
Zone* prev_zone_;
DISALLOW_COPY_AND_ASSIGN(DiscardableZoneScope);
}; };
void Parser::SetCachedData(ParseInfo* info) { void Parser::SetCachedData(ParseInfo* info) {
...@@ -4290,113 +4282,29 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -4290,113 +4282,29 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
function_name = ast_value_factory()->empty_string(); function_name = ast_value_factory()->empty_string();
} }
FunctionLiteral::EagerCompileHint eager_compile_hint = Scope* scope = NewFunctionScope(kind);
function_state_->next_function_is_parenthesized() SetLanguageMode(scope, language_mode);
? FunctionLiteral::kShouldEagerCompile ZoneList<Statement*>* body = NULL;
: 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;
int arity = -1; int arity = -1;
int materialized_literal_count = -1; int materialized_literal_count = -1;
int expected_property_count = -1; int expected_property_count = -1;
DuplicateFinder duplicate_finder(scanner()->unicode_cache()); DuplicateFinder duplicate_finder(scanner()->unicode_cache());
bool should_be_used_once_hint = false; bool should_be_used_once_hint = false;
bool has_duplicate_parameters; 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); FunctionState function_state(&function_state_, &scope_state_, scope, kind);
#ifdef DEBUG #ifdef DEBUG
this->scope()->SetScopeName(function_name); this->scope()->SetScopeName(function_name);
#endif #endif
ExpressionClassifier formals_classifier(this, &duplicate_finder); ExpressionClassifier formals_classifier(this, &duplicate_finder);
eager_compile_hint = function_state_->this_function_is_parenthesized()
? FunctionLiteral::kShouldEagerCompile
: FunctionLiteral::kShouldLazyCompile;
if (is_generator) { if (is_generator) {
// For generators, allocating variables in contexts is currently a win // For generators, allocating variables in contexts is currently a win
// because it minimizes the work needed to suspend and resume an // because it minimizes the work needed to suspend and resume an
...@@ -4429,6 +4337,43 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -4429,6 +4337,43 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// which says whether we need to create an arguments adaptor frame). // which says whether we need to create an arguments adaptor frame).
if (formals.has_rest) arity--; 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? // Eager or lazy parse?
// If is_lazily_parsed, we'll parse lazy. If we can set a bookmark, we'll // 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 // pass it to SkipLazyFunctionBody, which may use it to abort lazy
...@@ -4457,15 +4402,45 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -4457,15 +4402,45 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
} }
} }
if (!is_lazily_parsed) { 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, body = ParseEagerFunctionBody(function_name, pos, formals, kind,
function_type, CHECK_OK); function_type, CHECK_OK);
}
materialized_literal_count = function_state.materialized_literal_count(); materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count(); expected_property_count = function_state.expected_property_count();
if (use_temp_zone) { if (use_temp_zone) {
// If the preconditions are correct the function body should never be // If the preconditions are correct the function body should never be
// accessed, but do this anyway for better behaviour if they're wrong. // accessed, but do this anyway for better behaviour if they're wrong.
body = nullptr; body = NULL;
} }
} }
...@@ -4495,20 +4470,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -4495,20 +4470,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
} }
has_duplicate_parameters = has_duplicate_parameters =
!formals_classifier.is_valid_formal_parameter_list_without_duplicates(); !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 = FunctionLiteral::ParameterFlag duplicate_parameters =
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
: FunctionLiteral::kNoDuplicateParameters; : FunctionLiteral::kNoDuplicateParameters;
// Note that the FunctionLiteral needs to be created in the main Zone again.
FunctionLiteral* function_literal = factory()->NewFunctionLiteral( 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, expected_property_count, arity, duplicate_parameters, function_type,
eager_compile_hint, kind, pos); eager_compile_hint, kind, pos);
function_literal->set_function_token_position(function_token_pos); function_literal->set_function_token_position(function_token_pos);
......
...@@ -724,6 +724,7 @@ class Parser : public ParserBase<ParserTraits> { ...@@ -724,6 +724,7 @@ class Parser : public ParserBase<ParserTraits> {
private: private:
friend class ParserTraits; friend class ParserTraits;
friend class DiscardableZoneScope;
// Runtime encoding of different completion modes. // Runtime encoding of different completion modes.
enum CompletionKind { enum CompletionKind {
......
...@@ -35,19 +35,3 @@ function foo() { ...@@ -35,19 +35,3 @@ function foo() {
} }
assertEquals("hello world", 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