Commit 05696362 authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[parser] Skipping inner funcs: fix preparsing super.

Super calls need to refer to .this_function, .new.target and this, and super
property references need to refer to .this_function and this, so that the
is_used for those variables will be set and they will be allocated correctly.

BUG=v8:5516

Change-Id: Idc58539fccad70c995e029051b59a67ea66bff91
Reviewed-on: https://chromium-review.googlesource.com/506094Reviewed-by: 's avatarDaniel Vogelheim <vogelheim@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45376}
parent e33fd307
......@@ -660,7 +660,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
}
// Inform the scope that the corresponding code uses "super".
void RecordSuperPropertyUsage() { scope_uses_super_property_ = true; }
void RecordSuperPropertyUsage() {
DCHECK((IsConciseMethod(function_kind()) ||
IsAccessorFunction(function_kind()) ||
IsClassConstructor(function_kind())));
scope_uses_super_property_ = true;
}
// Does this scope access "super" property (super.foo).
bool uses_super_property() const { return scope_uses_super_property_; }
......
......@@ -335,8 +335,7 @@ bool PreParsedScopeData::ScopeNeedsData(Scope* scope) {
if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
// Default constructors don't need data (they cannot contain inner functions
// defined by the user). Other functions do.
return (scope->AsDeclarationScope()->function_kind() &
kDefaultConstructor) == 0;
return !IsDefaultConstructor(scope->AsDeclarationScope()->function_kind());
}
if (!scope->is_hidden()) {
for (Variable* var : *scope->locals()) {
......
......@@ -1521,10 +1521,29 @@ class PreParser : public ParserBase<PreParser> {
}
V8_INLINE PreParserExpression NewSuperPropertyReference(int pos) {
if (track_unresolved_variables_) {
scope()->NewUnresolved(factory()->ast_node_factory(),
ast_value_factory()->this_function_string(), pos,
NORMAL_VARIABLE);
scope()->NewUnresolved(factory()->ast_node_factory(),
ast_value_factory()->this_string(), pos,
THIS_VARIABLE);
}
return PreParserExpression::Default();
}
V8_INLINE PreParserExpression NewSuperCallReference(int pos) {
if (track_unresolved_variables_) {
scope()->NewUnresolved(factory()->ast_node_factory(),
ast_value_factory()->this_function_string(), pos,
NORMAL_VARIABLE);
scope()->NewUnresolved(factory()->ast_node_factory(),
ast_value_factory()->new_target_string(), pos,
NORMAL_VARIABLE);
scope()->NewUnresolved(factory()->ast_node_factory(),
ast_value_factory()->this_string(), pos,
THIS_VARIABLE);
}
return PreParserExpression::SuperCallReference();
}
......
......@@ -163,6 +163,15 @@ TEST(PreParserScopeAnalysis) {
// Methods containing skippable functions. Cannot test at the laziness
// boundary, since there's no way to force eager parsing of a method.
{"class MyClass { constructor() {",
"} }",
" function test(%s) { %s }",
"(function test(%s) { %s })()",
true,
true,
false,
{0, 0, 0}},
{"class MyClass { mymethod() {",
"} }",
" function test(%s) { %s }",
......@@ -618,7 +627,6 @@ TEST(PreParserScopeAnalysis) {
{"try { } catch(var1) { var var1 = 3; function f() { var1 = 3; } }"},
// Classes
// FIXME(marja): Add more complex class cases.
{"class MyClass {}"},
{"var1 = class MyClass {}"},
{"var var1 = class MyClass {}"},
......@@ -628,6 +636,12 @@ TEST(PreParserScopeAnalysis) {
{"let var1 = class {}"},
{"const var1 = class {}"},
{"class MyClass { constructor() {} }"},
{"class MyClass { constructor() { var var1; } }"},
{"class MyClass { constructor() { var var1 = 11; } }"},
{"class MyClass { constructor() { var var1; function foo() { var1 = 11; "
"} } }"},
{"class MyClass { m() {} }"},
{"class MyClass { m() { var var1; } }"},
{"class MyClass { m() { var var1 = 11; } }"},
......@@ -638,6 +652,28 @@ TEST(PreParserScopeAnalysis) {
{"class MyClass { static m() { var var1 = 11; } }"},
{"class MyClass { static m() { var var1; function foo() { var1 = 11; } } "
"}"},
{"class MyBase {} class MyClass extends MyBase {}"},
{"class MyClass extends MyBase { constructor() {} }"},
{"class MyClass extends MyBase { constructor() { super(); } }"},
{"class MyClass extends MyBase { constructor() { var var1; } }"},
{"class MyClass extends MyBase { constructor() { var var1 = 11; } }"},
{"class MyClass extends MyBase { constructor() { var var1; function "
"foo() { var1 = 11; } } }"},
{"class MyClass extends MyBase { m() {} }"},
{"class MyClass extends MyBase { m() { super.foo; } }"},
{"class MyClass extends MyBase { m() { var var1; } }"},
{"class MyClass extends MyBase { m() { var var1 = 11; } }"},
{"class MyClass extends MyBase { m() { var var1; function foo() { var1 = "
"11; } } }"},
{"class MyClass extends MyBase { static m() {} }"},
{"class MyClass extends MyBase { static m() { super.foo; } }"},
{"class MyClass extends MyBase { static m() { var var1; } }"},
{"class MyClass extends MyBase { static m() { var var1 = 11; } }"},
{"class MyClass extends MyBase { static m() { var var1; function foo() { "
"var1 = 11; } } }"},
};
for (unsigned outer_ix = 0; outer_ix < arraysize(outers); ++outer_ix) {
......
......@@ -23,31 +23,38 @@ class ScopeTestHelper {
static void CompareScopes(Scope* baseline, Scope* scope,
bool precise_maybe_assigned) {
if (!scope->is_hidden()) {
for (auto baseline_local = baseline->locals()->begin(),
scope_local = scope->locals()->begin();
baseline_local != baseline->locals()->end();
++baseline_local, ++scope_local) {
if (scope_local->mode() == VAR || scope_local->mode() == LET ||
scope_local->mode() == CONST) {
// Sanity check the variable name. If this fails, the variable order
// is not deterministic.
CHECK_EQ(scope_local->raw_name()->length(),
baseline_local->raw_name()->length());
for (int i = 0; i < scope_local->raw_name()->length(); ++i) {
CHECK_EQ(scope_local->raw_name()->raw_data()[i],
baseline_local->raw_name()->raw_data()[i]);
}
CHECK_EQ(baseline->scope_type(), scope->scope_type());
CHECK_IMPLIES(baseline->is_declaration_scope(),
baseline->AsDeclarationScope()->function_kind() ==
scope->AsDeclarationScope()->function_kind());
CHECK_EQ(scope_local->location(), baseline_local->location());
if (precise_maybe_assigned) {
CHECK_EQ(scope_local->maybe_assigned(),
baseline_local->maybe_assigned());
} else {
STATIC_ASSERT(kMaybeAssigned > kNotAssigned);
CHECK_GE(scope_local->maybe_assigned(),
baseline_local->maybe_assigned());
}
if (!PreParsedScopeData::ScopeNeedsData(baseline)) {
return;
}
for (auto baseline_local = baseline->locals()->begin(),
scope_local = scope->locals()->begin();
baseline_local != baseline->locals()->end();
++baseline_local, ++scope_local) {
if (scope_local->mode() == VAR || scope_local->mode() == LET ||
scope_local->mode() == CONST) {
// Sanity check the variable name. If this fails, the variable order
// is not deterministic.
CHECK_EQ(scope_local->raw_name()->length(),
baseline_local->raw_name()->length());
for (int i = 0; i < scope_local->raw_name()->length(); ++i) {
CHECK_EQ(scope_local->raw_name()->raw_data()[i],
baseline_local->raw_name()->raw_data()[i]);
}
CHECK_EQ(scope_local->location(), baseline_local->location());
if (precise_maybe_assigned) {
CHECK_EQ(scope_local->maybe_assigned(),
baseline_local->maybe_assigned());
} else {
STATIC_ASSERT(kMaybeAssigned > kNotAssigned);
CHECK_GE(scope_local->maybe_assigned(),
baseline_local->maybe_assigned());
}
}
}
......
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