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

Parsing: Create the same scopes for non-simple params in PreParser & Parser.

Rationale:

- To do scope analysis based on PreParser, and use the result again when parsing
  later, PreParser and Parser need to produce the same Scopes and variable
  declarations in them.

- This is not the case for non-simple parameters: Parser creates an additional
  inner Scope where the declarations were, whereas PreParser does
  DeclareVariableName directly in the function Scope.

- So this CL fixes that by moving the Scope creation for non-simple parameters
  into ParserBase.

- As a side product (and a partial proof that this change makes sense),
  PreParser::ParseEagerFunctionBody is now gone.

BUG=v8:5516

Review-Url: https://codereview.chromium.org/2638333002
Cr-Commit-Position: refs/heads/master@{#42537}
parent 8b8c8df0
......@@ -101,6 +101,12 @@ struct FormalParametersBase {
// Used in functions where the return type is ExpressionT.
#define CHECK_OK CHECK_OK_CUSTOM(EmptyExpression)
#define CHECK_OK_VOID ok); \
if (!*ok) return; \
((void)0
#define DUMMY ) // to make indentation work
#undef DUMMY
// Common base class template shared between parser and pre-parser.
// The Impl parameter is the actual class of the parser/pre-parser,
// following the Curiously Recurring Template Pattern (CRTP).
......@@ -1224,6 +1230,12 @@ class ParserBase {
bool default_export, bool* ok);
StatementT ParseNativeDeclaration(bool* ok);
// Consumes the ending }.
void ParseFunctionBody(StatementListT result, IdentifierT function_name,
int pos, const FormalParametersT& parameters,
FunctionKind kind,
FunctionLiteral::FunctionType function_type, bool* ok);
// Under some circumstances, we allow preparsing to abort if the preparsed
// function is "long and trivial", and fully parse instead. Our current
// definition of "long and trivial" is:
......@@ -3901,6 +3913,105 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration(
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
}
template <typename Impl>
void ParserBase<Impl>::ParseFunctionBody(
typename ParserBase<Impl>::StatementListT result, IdentifierT function_name,
int pos, const FormalParametersT& parameters, FunctionKind kind,
FunctionLiteral::FunctionType function_type, bool* ok) {
static const int kFunctionNameAssignmentIndex = 0;
if (function_type == FunctionLiteral::kNamedExpression) {
DCHECK(!impl()->IsEmptyIdentifier(function_name));
// If we have a named function expression, we add a local variable
// declaration to the body of the function with the name of the
// function and let it refer to the function itself (closure).
// Not having parsed the function body, the language mode may still change,
// so we reserve a spot and create the actual const assignment later.
DCHECK_EQ(kFunctionNameAssignmentIndex, result->length());
result->Add(impl()->NullStatement(), zone());
}
DeclarationScope* function_scope = scope()->AsDeclarationScope();
DeclarationScope* inner_scope = function_scope;
BlockT inner_block = impl()->NullBlock();
StatementListT body = result;
if (!parameters.is_simple) {
inner_scope = NewVarblockScope();
inner_scope->set_start_position(scanner()->location().beg_pos);
inner_block = factory()->NewBlock(NULL, 8, true, kNoSourcePosition);
inner_block->set_scope(inner_scope);
body = inner_block->statements();
}
{
BlockState block_state(&scope_state_, inner_scope);
if (IsGeneratorFunction(kind)) {
impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, body, ok);
} else if (IsAsyncFunction(kind)) {
const bool accept_IN = true;
ParseAsyncFunctionBody(inner_scope, body, kind, FunctionBodyType::kNormal,
accept_IN, pos, CHECK_OK_VOID);
} else {
ParseStatementList(body, Token::RBRACE, CHECK_OK_VOID);
}
if (IsDerivedConstructor(kind)) {
body->Add(factory()->NewReturnStatement(impl()->ThisExpression(),
kNoSourcePosition),
zone());
}
}
Expect(Token::RBRACE, CHECK_OK_VOID);
scope()->set_end_position(scanner()->location().end_pos);
if (!parameters.is_simple) {
DCHECK_NOT_NULL(inner_scope);
DCHECK_EQ(function_scope, scope());
DCHECK_EQ(function_scope, inner_scope->outer_scope());
impl()->SetLanguageMode(function_scope, inner_scope->language_mode());
BlockT init_block =
impl()->BuildParameterInitializationBlock(parameters, CHECK_OK_VOID);
if (is_sloppy(inner_scope->language_mode())) {
impl()->InsertSloppyBlockFunctionVarBindings(inner_scope);
}
// TODO(littledan): Merge the two rejection blocks into one
if (IsAsyncFunction(kind)) {
init_block = impl()->BuildRejectPromiseOnException(init_block);
}
inner_scope->set_end_position(scanner()->location().end_pos);
if (inner_scope->FinalizeBlockScope() != nullptr) {
impl()->CheckConflictingVarDeclarations(inner_scope, CHECK_OK_VOID);
impl()->InsertShadowingVarBindingInitializers(inner_block);
}
inner_scope = nullptr;
result->Add(init_block, zone());
result->Add(inner_block, zone());
} else {
DCHECK_EQ(inner_scope, function_scope);
if (is_sloppy(function_scope->language_mode())) {
impl()->InsertSloppyBlockFunctionVarBindings(function_scope);
}
}
if (!IsArrowFunction(kind)) {
// Declare arguments after parsing the function since lexical 'arguments'
// masks the arguments object. Declare arguments before declaring the
// function var since the arguments object masks 'function arguments'.
function_scope->DeclareArguments(ast_value_factory());
}
impl()->CreateFunctionNameAssignment(function_name, pos, function_type,
function_scope, result,
kFunctionNameAssignmentIndex);
impl()->MarkCollectedTailCallExpressions();
}
template <typename Impl>
void ParserBase<Impl>::CheckArityRestrictions(int param_count,
FunctionKind function_kind,
......@@ -4064,9 +4175,11 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
}
if (!is_lazy_top_level_function) {
Consume(Token::LBRACE);
body = impl()->ParseEagerFunctionBody(
impl()->EmptyIdentifier(), kNoSourcePosition, formal_parameters,
kind, FunctionLiteral::kAnonymousExpression, CHECK_OK);
body = impl()->NewStatementList(8);
impl()->ParseFunctionBody(body, impl()->EmptyIdentifier(),
kNoSourcePosition, formal_parameters, kind,
FunctionLiteral::kAnonymousExpression,
CHECK_OK);
materialized_literal_count =
function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
......@@ -5563,6 +5676,7 @@ void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName(
}
}
#undef CHECK_OK_VOID
} // namespace internal
} // namespace v8
......
This diff is collapsed.
......@@ -340,6 +340,14 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Block* finally_block,
const CatchInfo& catch_info, int pos);
void ParseAndRewriteGeneratorFunctionBody(int pos, FunctionKind kind,
ZoneList<Statement*>* body,
bool* ok);
void CreateFunctionNameAssignment(const AstRawString* function_name, int pos,
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope,
ZoneList<Statement*>* result, int index);
Statement* DeclareFunction(const AstRawString* variable_name,
FunctionLiteral* function, VariableMode mode,
int pos, bool is_generator, bool is_async,
......@@ -533,13 +541,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Block* BuildParameterInitializationBlock(
const ParserFormalParameters& parameters, bool* ok);
Block* BuildRejectPromiseOnException(Block* block, bool* ok);
// Consumes the ending }.
ZoneList<Statement*>* ParseEagerFunctionBody(
const AstRawString* function_name, int pos,
const ParserFormalParameters& parameters, FunctionKind kind,
FunctionLiteral::FunctionType function_type, bool* ok);
Block* BuildRejectPromiseOnException(Block* block);
ZoneList<Statement*>* ParseFunction(
const AstRawString* function_name, int pos, FunctionKind kind,
......@@ -1025,8 +1027,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
auto* init_block = BuildParameterInitializationBlock(parameters, ok);
if (!*ok) return;
if (is_async) {
init_block = BuildRejectPromiseOnException(init_block, ok);
if (!*ok) return;
init_block = BuildRejectPromiseOnException(init_block);
}
if (init_block != nullptr) body->Add(init_block, zone());
}
......
......@@ -414,10 +414,11 @@ class PreParserList {
// These functions make list->Add(some_expression) work (and do nothing).
PreParserList() : length_(0), variables_(nullptr) {}
PreParserList* operator->() { return this; }
void Add(T, Zone* zone);
void Add(const T& element, Zone* zone);
int length() const { return length_; }
static PreParserList Null() { return PreParserList(-1); }
bool IsNull() const { return length_ == -1; }
void Set(int index, const T& element) {}
private:
explicit PreParserList(int n) : length_(n), variables_(nullptr) {}
......@@ -430,7 +431,7 @@ class PreParserList {
template <>
inline void PreParserList<PreParserExpression>::Add(
PreParserExpression expression, Zone* zone) {
const PreParserExpression& expression, Zone* zone) {
if (expression.variables_ != nullptr) {
DCHECK(FLAG_lazy_inner_functions);
DCHECK(zone != nullptr);
......@@ -445,7 +446,7 @@ inline void PreParserList<PreParserExpression>::Add(
}
template <typename T>
void PreParserList<T>::Add(T, Zone* zone) {
void PreParserList<T>::Add(const T& element, Zone* zone) {
++length_;
}
......@@ -939,11 +940,6 @@ class PreParser : public ParserBase<PreParser> {
// By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites.
V8_INLINE PreParserStatementList ParseEagerFunctionBody(
PreParserIdentifier function_name, int pos,
const PreParserFormalParameters& parameters, FunctionKind kind,
FunctionLiteral::FunctionType function_type, bool* ok);
// Indicates that we won't switch from the preparser to the preparser; we'll
// just stay where we are.
bool AllowsLazyParsingWithoutUnresolvedVariables() const { return false; }
......@@ -1075,6 +1071,16 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatement::Default();
}
V8_INLINE void ParseAndRewriteGeneratorFunctionBody(
int pos, FunctionKind kind, PreParserStatementList body, bool* ok) {
ParseStatementList(body, Token::RBRACE, ok);
}
V8_INLINE void CreateFunctionNameAssignment(
PreParserIdentifier function_name, int pos,
FunctionLiteral::FunctionType function_type,
DeclarationScope* function_scope, PreParserStatementList result,
int index) {}
V8_INLINE PreParserExpression RewriteDoExpression(PreParserStatement body,
int pos, bool* ok) {
return PreParserExpression::Default();
......@@ -1328,6 +1334,23 @@ class PreParser : public ParserBase<PreParser> {
return loop;
}
V8_INLINE PreParserStatement BuildParameterInitializationBlock(
const PreParserFormalParameters& parameters, bool* ok) {
return PreParserStatement::Default();
}
V8_INLINE PreParserStatement
BuildRejectPromiseOnException(PreParserStatement init_block) {
return PreParserStatement::Default();
}
V8_INLINE void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) {
scope->HoistSloppyBlockFunctions(nullptr);
}
V8_INLINE void InsertShadowingVarBindingInitializers(
PreParserStatement block) {}
V8_INLINE PreParserExpression
NewThrowReferenceError(MessageTemplate::Template message, int pos) {
return PreParserExpression::Default();
......@@ -1623,29 +1646,6 @@ PreParserExpression PreParser::SpreadCallNew(PreParserExpression function,
return factory()->NewCallNew(function, args, pos);
}
PreParserStatementList PreParser::ParseEagerFunctionBody(
PreParserIdentifier function_name, int pos,
const PreParserFormalParameters& parameters, FunctionKind kind,
FunctionLiteral::FunctionType function_type, bool* ok) {
PreParserStatementList result;
DeclarationScope* inner_scope = scope()->AsDeclarationScope();
if (!parameters.is_simple) inner_scope = NewVarblockScope();
{
BlockState block_state(&scope_state_, inner_scope);
ParseStatementList(result, Token::RBRACE, ok);
if (!*ok) return PreParserStatementList();
}
Expect(Token::RBRACE, ok);
if (is_sloppy(inner_scope->language_mode())) {
inner_scope->HoistSloppyBlockFunctions(nullptr);
}
return result;
}
PreParserExpression PreParser::CloseTemplateLiteral(TemplateLiteralState* state,
int start,
PreParserExpression tag) {
......
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