PreParsing inner funcs: make scope analysis more complete.

This adds tracking the following:
- Declarations created by catch (potentially destructuring)
- Declarations created by for-each (potentially destructuring)
- Class declarations

BUG=v8:5501, v8:5516

Review-Url: https://codereview.chromium.org/2617923003
Cr-Commit-Position: refs/heads/master@{#42129}
This commit is contained in:
marja 2017-01-09 01:41:54 -08:00 committed by Commit bot
parent 9e65ecd957
commit d17558bc49
4 changed files with 99 additions and 51 deletions

View File

@ -1032,11 +1032,14 @@ void Scope::DeclareVariableName(const AstRawString* name, VariableMode mode) {
if (mode == VAR && !is_declaration_scope()) {
return GetDeclarationScope()->DeclareVariableName(name, mode);
}
DCHECK(!is_catch_scope());
DCHECK(!is_with_scope());
DCHECK(!is_eval_scope());
DCHECK(is_declaration_scope() ||
(IsLexicalVariableMode(mode) && is_block_scope()));
// Unlike DeclareVariable, DeclareVariableName allows declaring variables in
// catch scopes: Parser::RewriteCatchPattern bypasses DeclareVariable by
// calling DeclareLocal directly, and it doesn't make sense to add a similar
// bypass mechanism for PreParser.
DCHECK(is_declaration_scope() || (IsLexicalVariableMode(mode) &&
(is_block_scope() || is_catch_scope())));
DCHECK(scope_info_.is_null());
// Declare the variable in the declaration scope.

View File

@ -1892,6 +1892,7 @@ void Parser::DesugarBindingInForEachStatement(ForInfo* for_info,
Block** body_block,
Expression** each_variable,
bool* ok) {
DCHECK(for_info->parsing_result.declarations.length() == 1);
DeclarationParsingResult::Declaration& decl =
for_info->parsing_result.declarations[0];
Variable* temp = NewTemporary(ast_value_factory()->dot_for_string());

View File

@ -1049,7 +1049,22 @@ class PreParser : public ParserBase<PreParser> {
PreParserStatementList cases, Scope* scope) {
return PreParserStatement::Default();
}
V8_INLINE void RewriteCatchPattern(CatchInfo* catch_info, bool* ok) {}
V8_INLINE void RewriteCatchPattern(CatchInfo* catch_info, bool* ok) {
if (track_unresolved_variables_) {
if (catch_info->name.string_ != nullptr) {
// Unlike in the parser, we need to declare the catch variable as LET
// variable, so that it won't get hoisted out of the scope.
catch_info->scope->DeclareVariableName(catch_info->name.string_, LET);
}
if (catch_info->pattern.variables_ != nullptr) {
for (auto variable : *catch_info->pattern.variables_) {
scope()->DeclareVariableName(variable->raw_name(), LET);
}
}
}
}
V8_INLINE void ValidateCatchBlock(const CatchInfo& catch_info, bool* ok) {}
V8_INLINE PreParserStatement RewriteTryStatement(
PreParserStatement try_block, PreParserStatement catch_block,
@ -1084,6 +1099,12 @@ class PreParser : public ParserBase<PreParser> {
DeclareClass(PreParserIdentifier variable_name, PreParserExpression value,
ZoneList<const AstRawString*>* names, int class_token_pos,
int end_pos, bool* ok) {
// Preparser shouldn't be used in contexts where we need to track the names.
DCHECK_NULL(names);
if (variable_name.string_ != nullptr) {
DCHECK(track_unresolved_variables_);
scope()->DeclareVariableName(variable_name.string_, LET);
}
return PreParserStatement::Default();
}
V8_INLINE void DeclareClassVariable(PreParserIdentifier name,
@ -1264,9 +1285,18 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE PreParserStatement RewriteForVarInLegacy(const ForInfo& for_info) {
return PreParserStatement::Null();
}
V8_INLINE void DesugarBindingInForEachStatement(
ForInfo* for_info, PreParserStatement* body_block,
PreParserExpression* each_variable, bool* ok) {}
PreParserExpression* each_variable, bool* ok) {
if (track_unresolved_variables_) {
DCHECK(for_info->parsing_result.declarations.length() == 1);
DeclareAndInitializeVariables(
PreParserStatement::Default(), &for_info->parsing_result.descriptor,
&for_info->parsing_result.declarations[0], nullptr, ok);
}
}
V8_INLINE PreParserStatement CreateForEachStatementTDZ(
PreParserStatement init_block, const ForInfo& for_info, bool* ok) {
return init_block;

View File

@ -8805,62 +8805,76 @@ TEST(NoPessimisticContextAllocation) {
{"function inner() { ({y, x: my_var}) => { }}", false},
{"function inner() { ({y, x: my_var} = {y: 0, x: 0}) => my_var;}", false},
{"function inner() { ({y, x: my_var} = {y: 0, x: 0}) => { }}", false},
{"function inner() { try { } catch (my_var) { my_var; } }", false},
{"function inner() { try { } catch ([a, my_var, b]) { my_var; } }",
false},
{"function inner() { try { } catch ({x: my_var}) { my_var; } }", false},
{"function inner() { try { } catch ({y, x: my_var}) { my_var; } }",
false},
{"function inner() { try { } catch ({my_var}) { my_var; } }", false},
{"function inner() { for (let my_var in {}) { my_var; } }", false},
{"function inner() { for (let my_var in {}) { } }", false},
{"function inner() { for (let my_var of []) { my_var; } }", false},
{"function inner() { for (let my_var of []) { } }", false},
{"function inner() { for (let [a, my_var, b] in {}) { my_var; } }",
false},
{"function inner() { for (let [a, my_var, b] of []) { my_var; } }",
false},
{"function inner() { for (let {x: my_var} in {}) { my_var; } }", false},
{"function inner() { for (let {x: my_var} of []) { my_var; } }", false},
{"function inner() { for (let {my_var} in {}) { my_var; } }", false},
{"function inner() { for (let {my_var} of []) { my_var; } }", false},
{"function inner() { for (let {y, x: my_var} in {}) { my_var; } }",
false},
{"function inner() { for (let {y, x: my_var} of []) { my_var; } }",
false},
{"function inner() { for (let {a, my_var} in {}) { my_var; } }", false},
{"function inner() { for (let {a, my_var} of []) { my_var; } }", false},
{"function inner() { for (var my_var in {}) { my_var; } }", false},
{"function inner() { for (var my_var in {}) { } }", false},
{"function inner() { for (var my_var of []) { my_var; } }", false},
{"function inner() { for (var my_var of []) { } }", false},
{"function inner() { for (var [a, my_var, b] in {}) { my_var; } }",
false},
{"function inner() { for (var [a, my_var, b] of []) { my_var; } }",
false},
{"function inner() { for (var {x: my_var} in {}) { my_var; } }", false},
{"function inner() { for (var {x: my_var} of []) { my_var; } }", false},
{"function inner() { for (var {my_var} in {}) { my_var; } }", false},
{"function inner() { for (var {my_var} of []) { my_var; } }", false},
{"function inner() { for (var {y, x: my_var} in {}) { my_var; } }",
false},
{"function inner() { for (var {y, x: my_var} of []) { my_var; } }",
false},
{"function inner() { for (var {a, my_var} in {}) { my_var; } }", false},
{"function inner() { for (var {a, my_var} of []) { my_var; } }", false},
{"function inner() { for (var my_var in {}) { } my_var; }", false},
{"function inner() { for (var my_var of []) { } my_var; }", false},
{"function inner() { for (var [a, my_var, b] in {}) { } my_var; }",
false},
{"function inner() { for (var [a, my_var, b] of []) { } my_var; }",
false},
{"function inner() { for (var {x: my_var} in {}) { } my_var; }", false},
{"function inner() { for (var {x: my_var} of []) { } my_var; }", false},
{"function inner() { for (var {my_var} in {}) { } my_var; }", false},
{"function inner() { for (var {my_var} of []) { } my_var; }", false},
{"function inner() { for (var {y, x: my_var} in {}) { } my_var; }",
false},
{"function inner() { for (var {y, x: my_var} of []) { } my_var; }",
false},
{"function inner() { for (var {a, my_var} in {}) { } my_var; }", false},
{"function inner() { for (var {a, my_var} of []) { } my_var; }", false},
{"function inner() { class my_var {}; my_var }", false},
// In the following cases we still context allocate pessimistically:
{"function inner() { function my_var() {} my_var; }", true},
{"function inner() { if (true) { function my_var() {} } my_var; }",
true},
{"function inner() { try { } catch (my_var) { my_var; } }", true},
{"function inner() { try { } catch ([a, my_var, b]) { my_var; } }", true},
{"function inner() { try { } catch ({x: my_var}) { my_var; } }", true},
{"function inner() { try { } catch ({y, x: my_var}) { my_var; } }", true},
{"function inner() { try { } catch ({my_var}) { my_var; } }", true},
{"function inner() { for (let my_var = 0; my_var < 1; ++my_var) { my_var "
"} }",
true},
{"function inner() { for (let a = 0, my_var = 0; my_var < 1; ++my_var) { "
"my_var } }",
true},
{"function inner() { for (let my_var in {}) { my_var; } }", true},
{"function inner() { for (let my_var in {}) { } }", true},
{"function inner() { for (let my_var of []) { my_var; } }", true},
{"function inner() { for (let my_var of []) { } }", true},
{"function inner() { for (let [a, my_var, b] in {}) { my_var; } }", true},
{"function inner() { for (let [a, my_var, b] of []) { my_var; } }", true},
{"function inner() { for (let {x: my_var} in {}) { my_var; } }", true},
{"function inner() { for (let {x: my_var} of []) { my_var; } }", true},
{"function inner() { for (let {my_var} in {}) { my_var; } }", true},
{"function inner() { for (let {my_var} of []) { my_var; } }", true},
{"function inner() { for (let {y, x: my_var} in {}) { my_var; } }", true},
{"function inner() { for (let {y, x: my_var} of []) { my_var; } }", true},
{"function inner() { for (let {a, my_var} in {}) { my_var; } }", true},
{"function inner() { for (let {a, my_var} of []) { my_var; } }", true},
{"function inner() { for (var my_var in {}) { my_var; } }", true},
{"function inner() { for (var my_var in {}) { } }", true},
{"function inner() { for (var my_var of []) { my_var; } }", true},
{"function inner() { for (var my_var of []) { } }", true},
{"function inner() { for (var [a, my_var, b] in {}) { my_var; } }", true},
{"function inner() { for (var [a, my_var, b] of []) { my_var; } }", true},
{"function inner() { for (var {x: my_var} in {}) { my_var; } }", true},
{"function inner() { for (var {x: my_var} of []) { my_var; } }", true},
{"function inner() { for (var {my_var} in {}) { my_var; } }", true},
{"function inner() { for (var {my_var} of []) { my_var; } }", true},
{"function inner() { for (var {y, x: my_var} in {}) { my_var; } }", true},
{"function inner() { for (var {y, x: my_var} of []) { my_var; } }", true},
{"function inner() { for (var {a, my_var} in {}) { my_var; } }", true},
{"function inner() { for (var {a, my_var} of []) { my_var; } }", true},
{"function inner() { for (var my_var in {}) { } my_var; }", true},
{"function inner() { for (var my_var of []) { } my_var; }", true},
{"function inner() { for (var [a, my_var, b] in {}) { } my_var; }", true},
{"function inner() { for (var [a, my_var, b] of []) { } my_var; }", true},
{"function inner() { for (var {x: my_var} in {}) { } my_var; }", true},
{"function inner() { for (var {x: my_var} of []) { } my_var; }", true},
{"function inner() { for (var {my_var} in {}) { } my_var; }", true},
{"function inner() { for (var {my_var} of []) { } my_var; }", true},
{"function inner() { for (var {y, x: my_var} in {}) { } my_var; }", true},
{"function inner() { for (var {y, x: my_var} of []) { } my_var; }", true},
{"function inner() { for (var {a, my_var} in {}) { } my_var; }", true},
{"function inner() { for (var {a, my_var} of []) { } my_var; }", true},
{"function inner() { class my_var {}; my_var }", true},
};
for (unsigned i = 0; i < arraysize(inners); ++i) {