Commit 3f2b5017 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[parser] Handle 'this' with a special ThisExpression rather than VariableProxy

"this" is a very common expression. By using a single ThisExpression object
we can both avoid allocating many unnecessary VariableProxies and specialize
the resolution of this since we know where it's declared up-front. This also
avoids having to special-case "this" reference handling in the paths that would
behave differently for "this" than for regular references; e.g., with-scopes.

The tricky pieces are due to DebugEvaluate and this/super() used as default
parameters of arrow functions. In the former case we replace the WITH_SCOPE
with FUNCTION_SCOPE so that we make sure that "this" is intercepted, and still
rely on regular dynamic variable lookup. Arrow functions are dealt with by
marking "this" use in ArrowHeadParsingScopes. If the parenthesized expression
ends up being an arrow function, we force context allocate on the outer scope
(and mark "has_this_reference" on the FUNCTION_SCOPE so DebugEvaluate in the
arrow function can expose "this").

The CL also removes the now unused ThisFunction AST node.

Change-Id: I0ca38ab92ff58c2f731e07db2fbe91df901681ef
Reviewed-on: https://chromium-review.googlesource.com/c/1448313Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59393}
parent 66ddc07b
...@@ -468,7 +468,7 @@ void AstTraversalVisitor<Subclass>::VisitCompareOperation( ...@@ -468,7 +468,7 @@ void AstTraversalVisitor<Subclass>::VisitCompareOperation(
} }
template <class Subclass> template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitThisFunction(ThisFunction* expr) { void AstTraversalVisitor<Subclass>::VisitThisExpression(ThisExpression* expr) {
PROCESS_EXPRESSION(expr); PROCESS_EXPRESSION(expr);
} }
...@@ -556,7 +556,6 @@ template <class Subclass> ...@@ -556,7 +556,6 @@ template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference( void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference(
SuperPropertyReference* expr) { SuperPropertyReference* expr) {
PROCESS_EXPRESSION(expr); PROCESS_EXPRESSION(expr);
RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var()));
RECURSE_EXPRESSION(Visit(expr->home_object())); RECURSE_EXPRESSION(Visit(expr->home_object()));
} }
...@@ -564,7 +563,6 @@ template <class Subclass> ...@@ -564,7 +563,6 @@ template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitSuperCallReference( void AstTraversalVisitor<Subclass>::VisitSuperCallReference(
SuperCallReference* expr) { SuperCallReference* expr) {
PROCESS_EXPRESSION(expr); PROCESS_EXPRESSION(expr);
RECURSE_EXPRESSION(VisitVariableProxy(expr->this_var()));
RECURSE_EXPRESSION(VisitVariableProxy(expr->new_target_var())); RECURSE_EXPRESSION(VisitVariableProxy(expr->new_target_var()));
RECURSE_EXPRESSION(VisitVariableProxy(expr->this_function_var())); RECURSE_EXPRESSION(VisitVariableProxy(expr->this_function_var()));
} }
......
...@@ -175,8 +175,8 @@ VariableProxy::VariableProxy(Variable* var, int start_position) ...@@ -175,8 +175,8 @@ VariableProxy::VariableProxy(Variable* var, int start_position)
: Expression(start_position, kVariableProxy), : Expression(start_position, kVariableProxy),
raw_name_(var->raw_name()), raw_name_(var->raw_name()),
next_unresolved_(nullptr) { next_unresolved_(nullptr) {
bit_field_ |= IsThisField::encode(var->is_this()) | DCHECK(!var->is_this());
IsAssignedField::encode(false) | bit_field_ |= IsAssignedField::encode(false) |
IsResolvedField::encode(false) | IsResolvedField::encode(false) |
HoleCheckModeField::encode(HoleCheckMode::kElided); HoleCheckModeField::encode(HoleCheckMode::kElided);
BindTo(var); BindTo(var);
...@@ -191,7 +191,7 @@ VariableProxy::VariableProxy(const VariableProxy* copy_from) ...@@ -191,7 +191,7 @@ VariableProxy::VariableProxy(const VariableProxy* copy_from)
} }
void VariableProxy::BindTo(Variable* var) { void VariableProxy::BindTo(Variable* var) {
DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name()); DCHECK_EQ(raw_name(), var->raw_name());
set_var(var); set_var(var);
set_is_resolved(); set_is_resolved();
var->set_is_used(); var->set_is_used();
......
...@@ -100,7 +100,7 @@ namespace internal { ...@@ -100,7 +100,7 @@ namespace internal {
V(SuperCallReference) \ V(SuperCallReference) \
V(SuperPropertyReference) \ V(SuperPropertyReference) \
V(TemplateLiteral) \ V(TemplateLiteral) \
V(ThisFunction) \ V(ThisExpression) \
V(Throw) \ V(Throw) \
V(UnaryOperation) \ V(UnaryOperation) \
V(VariableProxy) \ V(VariableProxy) \
...@@ -1516,11 +1516,15 @@ class ArrayLiteral final : public AggregateLiteral { ...@@ -1516,11 +1516,15 @@ class ArrayLiteral final : public AggregateLiteral {
enum class HoleCheckMode { kRequired, kElided }; enum class HoleCheckMode { kRequired, kElided };
class ThisExpression final : public Expression {
private:
friend class AstNodeFactory;
ThisExpression() : Expression(kNoSourcePosition, kThisExpression) {}
};
class VariableProxy final : public Expression { class VariableProxy final : public Expression {
public: public:
bool IsValidReferenceExpression() const { bool IsValidReferenceExpression() const { return !is_new_target(); }
return !is_this() && !is_new_target();
}
Handle<String> name() const { return raw_name()->string(); } Handle<String> name() const { return raw_name()->string(); }
const AstRawString* raw_name() const { const AstRawString* raw_name() const {
...@@ -1541,8 +1545,6 @@ class VariableProxy final : public Expression { ...@@ -1541,8 +1545,6 @@ class VariableProxy final : public Expression {
return Scanner::Location(position(), position() + raw_name()->length()); return Scanner::Location(position(), position() + raw_name()->length());
} }
bool is_this() const { return IsThisField::decode(bit_field_); }
bool is_assigned() const { return IsAssignedField::decode(bit_field_); } bool is_assigned() const { return IsAssignedField::decode(bit_field_); }
void set_is_assigned() { void set_is_assigned() {
bit_field_ = IsAssignedField::update(bit_field_, true); bit_field_ = IsAssignedField::update(bit_field_, true);
...@@ -1615,8 +1617,8 @@ class VariableProxy final : public Expression { ...@@ -1615,8 +1617,8 @@ class VariableProxy final : public Expression {
: Expression(start_position, kVariableProxy), : Expression(start_position, kVariableProxy),
raw_name_(name), raw_name_(name),
next_unresolved_(nullptr) { next_unresolved_(nullptr) {
bit_field_ |= IsThisField::encode(variable_kind == THIS_VARIABLE) | DCHECK_NE(THIS_VARIABLE, variable_kind);
IsAssignedField::encode(false) | bit_field_ |= IsAssignedField::encode(false) |
IsResolvedField::encode(false) | IsResolvedField::encode(false) |
IsRemovedFromUnresolvedField::encode(false) | IsRemovedFromUnresolvedField::encode(false) |
HoleCheckModeField::encode(HoleCheckMode::kElided); HoleCheckModeField::encode(HoleCheckMode::kElided);
...@@ -1624,9 +1626,8 @@ class VariableProxy final : public Expression { ...@@ -1624,9 +1626,8 @@ class VariableProxy final : public Expression {
explicit VariableProxy(const VariableProxy* copy_from); explicit VariableProxy(const VariableProxy* copy_from);
class IsThisField : public BitField<bool, Expression::kNextBitFieldIndex, 1> { class IsAssignedField
}; : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
class IsAssignedField : public BitField<bool, IsThisField::kNext, 1> {};
class IsResolvedField : public BitField<bool, IsAssignedField::kNext, 1> {}; class IsResolvedField : public BitField<bool, IsAssignedField::kNext, 1> {};
class IsRemovedFromUnresolvedField class IsRemovedFromUnresolvedField
: public BitField<bool, IsResolvedField::kNext, 1> {}; : public BitField<bool, IsResolvedField::kNext, 1> {};
...@@ -2571,56 +2572,41 @@ class NativeFunctionLiteral final : public Expression { ...@@ -2571,56 +2572,41 @@ class NativeFunctionLiteral final : public Expression {
}; };
class ThisFunction final : public Expression {
private:
friend class AstNodeFactory;
explicit ThisFunction(int pos) : Expression(pos, kThisFunction) {}
};
class SuperPropertyReference final : public Expression { class SuperPropertyReference final : public Expression {
public: public:
VariableProxy* this_var() const { return this_var_; }
Expression* home_object() const { return home_object_; } Expression* home_object() const { return home_object_; }
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
SuperPropertyReference(VariableProxy* this_var, Expression* home_object, // We take in ThisExpression* only as a proof that it was accessed.
int pos) SuperPropertyReference(Expression* home_object, int pos)
: Expression(pos, kSuperPropertyReference), : Expression(pos, kSuperPropertyReference), home_object_(home_object) {
this_var_(this_var),
home_object_(home_object) {
DCHECK(this_var->is_this());
DCHECK(home_object->IsProperty()); DCHECK(home_object->IsProperty());
} }
VariableProxy* this_var_;
Expression* home_object_; Expression* home_object_;
}; };
class SuperCallReference final : public Expression { class SuperCallReference final : public Expression {
public: public:
VariableProxy* this_var() const { return this_var_; }
VariableProxy* new_target_var() const { return new_target_var_; } VariableProxy* new_target_var() const { return new_target_var_; }
VariableProxy* this_function_var() const { return this_function_var_; } VariableProxy* this_function_var() const { return this_function_var_; }
private: private:
friend class AstNodeFactory; friend class AstNodeFactory;
SuperCallReference(VariableProxy* this_var, VariableProxy* new_target_var, // We take in ThisExpression* only as a proof that it was accessed.
SuperCallReference(VariableProxy* new_target_var,
VariableProxy* this_function_var, int pos) VariableProxy* this_function_var, int pos)
: Expression(pos, kSuperCallReference), : Expression(pos, kSuperCallReference),
this_var_(this_var),
new_target_var_(new_target_var), new_target_var_(new_target_var),
this_function_var_(this_function_var) { this_function_var_(this_function_var) {
DCHECK(this_var->is_this());
DCHECK(new_target_var->raw_name()->IsOneByteEqualTo(".new.target")); DCHECK(new_target_var->raw_name()->IsOneByteEqualTo(".new.target"));
DCHECK(this_function_var->raw_name()->IsOneByteEqualTo(".this_function")); DCHECK(this_function_var->raw_name()->IsOneByteEqualTo(".this_function"));
} }
VariableProxy* this_var_;
VariableProxy* new_target_var_; VariableProxy* new_target_var_;
VariableProxy* this_function_var_; VariableProxy* this_function_var_;
}; };
...@@ -2802,6 +2788,7 @@ class AstNodeFactory final { ...@@ -2802,6 +2788,7 @@ class AstNodeFactory final {
: zone_(zone), : zone_(zone),
ast_value_factory_(ast_value_factory), ast_value_factory_(ast_value_factory),
empty_statement_(new (zone) class EmptyStatement()), empty_statement_(new (zone) class EmptyStatement()),
this_expression_(new (zone) class ThisExpression()),
failure_expression_(new (zone) class FailureExpression()) {} failure_expression_(new (zone) class FailureExpression()) {}
AstNodeFactory* ast_node_factory() { return this; } AstNodeFactory* ast_node_factory() { return this; }
...@@ -2956,6 +2943,10 @@ class AstNodeFactory final { ...@@ -2956,6 +2943,10 @@ class AstNodeFactory final {
return empty_statement_; return empty_statement_;
} }
class ThisExpression* ThisExpression() {
return this_expression_;
}
class FailureExpression* FailureExpression() { class FailureExpression* FailureExpression() {
return failure_expression_; return failure_expression_;
} }
...@@ -3266,22 +3257,16 @@ class AstNodeFactory final { ...@@ -3266,22 +3257,16 @@ class AstNodeFactory final {
return new (zone_) DoExpression(block, result, pos); return new (zone_) DoExpression(block, result, pos);
} }
ThisFunction* NewThisFunction(int pos) { SuperPropertyReference* NewSuperPropertyReference(Expression* home_object,
return new (zone_) ThisFunction(pos);
}
SuperPropertyReference* NewSuperPropertyReference(VariableProxy* this_var,
Expression* home_object,
int pos) { int pos) {
return new (zone_) SuperPropertyReference(this_var, home_object, pos); return new (zone_) SuperPropertyReference(home_object, pos);
} }
SuperCallReference* NewSuperCallReference(VariableProxy* this_var, SuperCallReference* NewSuperCallReference(VariableProxy* new_target_var,
VariableProxy* new_target_var,
VariableProxy* this_function_var, VariableProxy* this_function_var,
int pos) { int pos) {
return new (zone_) return new (zone_)
SuperCallReference(this_var, new_target_var, this_function_var, pos); SuperCallReference(new_target_var, this_function_var, pos);
} }
EmptyParentheses* NewEmptyParentheses(int pos) { EmptyParentheses* NewEmptyParentheses(int pos) {
...@@ -3319,6 +3304,7 @@ class AstNodeFactory final { ...@@ -3319,6 +3304,7 @@ class AstNodeFactory final {
Zone* zone_; Zone* zone_;
AstValueFactory* ast_value_factory_; AstValueFactory* ast_value_factory_;
class EmptyStatement* empty_statement_; class EmptyStatement* empty_statement_;
class ThisExpression* this_expression_;
class FailureExpression* failure_expression_; class FailureExpression* failure_expression_;
}; };
......
...@@ -500,8 +500,7 @@ void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) { ...@@ -500,8 +500,7 @@ void CallPrinter::VisitImportCallExpression(ImportCallExpression* node) {
Print(")"); Print(")");
} }
void CallPrinter::VisitThisFunction(ThisFunction* node) {} void CallPrinter::VisitThisExpression(ThisExpression* node) { Print("this"); }
void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {} void CallPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {}
...@@ -1387,11 +1386,10 @@ void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) { ...@@ -1387,11 +1386,10 @@ void AstPrinter::VisitImportCallExpression(ImportCallExpression* node) {
Visit(node->argument()); Visit(node->argument());
} }
void AstPrinter::VisitThisFunction(ThisFunction* node) { void AstPrinter::VisitThisExpression(ThisExpression* node) {
IndentedScope indent(this, "THIS-FUNCTION", node->position()); IndentedScope indent(this, "THIS-EXPRESSION", node->position());
} }
void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) { void AstPrinter::VisitSuperPropertyReference(SuperPropertyReference* node) {
IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position()); IndentedScope indent(this, "SUPER-PROPERTY-REFERENCE", node->position());
} }
......
...@@ -110,10 +110,8 @@ DeclarationScope::DeclarationScope(Zone* zone, ...@@ -110,10 +110,8 @@ DeclarationScope::DeclarationScope(Zone* zone,
: Scope(zone), function_kind_(kNormalFunction), params_(4, zone) { : Scope(zone), function_kind_(kNormalFunction), params_(4, zone) {
DCHECK_EQ(scope_type_, SCRIPT_SCOPE); DCHECK_EQ(scope_type_, SCRIPT_SCOPE);
SetDefaults(); SetDefaults();
receiver_ = DeclareDynamicGlobal(ast_value_factory->this_string(),
// Make sure that if we don't find the global 'this', it won't be declared as THIS_VARIABLE, this);
// a regular dynamic global by predeclaring it with the right variable kind.
DeclareDynamicGlobal(ast_value_factory->this_string(), THIS_VARIABLE, this);
} }
DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope, DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope,
...@@ -241,6 +239,9 @@ void DeclarationScope::SetDefaults() { ...@@ -241,6 +239,9 @@ void DeclarationScope::SetDefaults() {
has_arguments_parameter_ = false; has_arguments_parameter_ = false;
scope_uses_super_property_ = false; scope_uses_super_property_ = false;
has_checked_syntax_ = false; has_checked_syntax_ = false;
has_this_reference_ = false;
has_this_declaration_ =
(is_function_scope() && !is_arrow_scope()) || is_module_scope();
has_rest_ = false; has_rest_ = false;
receiver_ = nullptr; receiver_ = nullptr;
new_target_ = nullptr; new_target_ = nullptr;
...@@ -333,15 +334,16 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, ...@@ -333,15 +334,16 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
Scope* outer_scope = nullptr; Scope* outer_scope = nullptr;
while (!scope_info.is_null()) { while (!scope_info.is_null()) {
if (scope_info->scope_type() == WITH_SCOPE) { if (scope_info->scope_type() == WITH_SCOPE) {
// For scope analysis, debug-evaluate is equivalent to a with scope.
outer_scope =
new (zone) Scope(zone, WITH_SCOPE, handle(scope_info, isolate));
// TODO(yangguo): Remove once debug-evaluate properly keeps track of the
// function scope in which we are evaluating.
if (scope_info->IsDebugEvaluateScope()) { if (scope_info->IsDebugEvaluateScope()) {
outer_scope = new (zone)
DeclarationScope(zone, FUNCTION_SCOPE, handle(scope_info, isolate));
outer_scope->set_is_debug_evaluate_scope(); outer_scope->set_is_debug_evaluate_scope();
} else {
// For scope analysis, debug-evaluate is equivalent to a with scope.
outer_scope =
new (zone) Scope(zone, WITH_SCOPE, handle(scope_info, isolate));
} }
} else if (scope_info->scope_type() == SCRIPT_SCOPE) { } else if (scope_info->scope_type() == SCRIPT_SCOPE) {
// If we reach a script scope, it's the outermost scope. Install the // If we reach a script scope, it's the outermost scope. Install the
// scope info of this script context onto the existing script scope to // scope info of this script context onto the existing script scope to
...@@ -571,20 +573,16 @@ bool DeclarationScope::Analyze(ParseInfo* info) { ...@@ -571,20 +573,16 @@ bool DeclarationScope::Analyze(ParseInfo* info) {
} }
void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) { void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) {
DCHECK(!already_resolved_);
DCHECK(is_declaration_scope());
DCHECK(has_this_declaration()); DCHECK(has_this_declaration());
bool derived_constructor = IsDerivedConstructor(function_kind_); bool derived_constructor = IsDerivedConstructor(function_kind_);
bool was_added;
Variable* var = receiver_ = new (zone())
Declare(zone(), ast_value_factory->this_string(), Variable(this, ast_value_factory->this_string(),
derived_constructor ? VariableMode::kConst : VariableMode::kVar, derived_constructor ? VariableMode::kConst : VariableMode::kVar,
THIS_VARIABLE, THIS_VARIABLE,
derived_constructor ? kNeedsInitialization : kCreatedInitialized, derived_constructor ? kNeedsInitialization : kCreatedInitialized,
kNotAssigned, &was_added); kNotAssigned);
DCHECK(was_added);
receiver_ = var;
} }
void DeclarationScope::DeclareArguments(AstValueFactory* ast_value_factory) { void DeclarationScope::DeclareArguments(AstValueFactory* ast_value_factory) {
...@@ -819,18 +817,14 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) { ...@@ -819,18 +817,14 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
return cache->variables_.Lookup(name); return cache->variables_.Lookup(name);
} }
VariableKind kind = NORMAL_VARIABLE; if (!is_module_scope()) {
if (location == VariableLocation::CONTEXT && DCHECK_NE(index, scope_info_->ReceiverContextSlotIndex());
index == scope_info_->ReceiverContextSlotIndex()) {
kind = THIS_VARIABLE;
} }
// TODO(marja, rossberg): Correctly declare FUNCTION, CLASS, NEW_TARGET, and
// ARGUMENTS bindings as their corresponding VariableKind.
bool was_added; bool was_added;
Variable* var = Variable* var =
cache->variables_.Declare(zone(), this, name, mode, kind, init_flag, cache->variables_.Declare(zone(), this, name, mode, NORMAL_VARIABLE,
maybe_assigned_flag, &was_added); init_flag, maybe_assigned_flag, &was_added);
DCHECK(was_added); DCHECK(was_added);
var->AllocateTo(location, index); var->AllocateTo(location, index);
return var; return var;
...@@ -1152,6 +1146,21 @@ const AstRawString* Scope::FindVariableDeclaredIn(Scope* scope, ...@@ -1152,6 +1146,21 @@ const AstRawString* Scope::FindVariableDeclaredIn(Scope* scope,
return nullptr; return nullptr;
} }
void DeclarationScope::DeserializeReceiver(AstValueFactory* ast_value_factory) {
if (is_script_scope()) {
DCHECK_NOT_NULL(receiver_);
return;
}
DCHECK(has_this_declaration());
DeclareThis(ast_value_factory);
if (is_debug_evaluate_scope()) {
receiver_->AllocateTo(VariableLocation::LOOKUP, -1);
} else {
receiver_->AllocateTo(VariableLocation::CONTEXT,
scope_info_->ReceiverContextSlotIndex());
}
}
bool DeclarationScope::AllocateVariables(ParseInfo* info) { bool DeclarationScope::AllocateVariables(ParseInfo* info) {
// Module variables must be allocated before variable resolution // Module variables must be allocated before variable resolution
// to ensure that UpdateNeedsHoleCheck() can detect import variables. // to ensure that UpdateNeedsHoleCheck() can detect import variables.
...@@ -1168,6 +1177,21 @@ bool DeclarationScope::AllocateVariables(ParseInfo* info) { ...@@ -1168,6 +1177,21 @@ bool DeclarationScope::AllocateVariables(ParseInfo* info) {
return true; return true;
} }
bool Scope::HasThisReference() const {
if (is_declaration_scope() && AsDeclarationScope()->has_this_reference()) {
return true;
}
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
if (!scope->is_declaration_scope() ||
!scope->AsDeclarationScope()->has_this_declaration()) {
if (scope->HasThisReference()) return true;
}
}
return false;
}
bool Scope::AllowsLazyParsingWithoutUnresolvedVariables( bool Scope::AllowsLazyParsingWithoutUnresolvedVariables(
const Scope* outer) const { const Scope* outer) const {
// If none of the outer scopes need to decide whether to context allocate // If none of the outer scopes need to decide whether to context allocate
...@@ -1260,9 +1284,9 @@ bool Scope::ShouldBanArguments() { ...@@ -1260,9 +1284,9 @@ bool Scope::ShouldBanArguments() {
DeclarationScope* Scope::GetReceiverScope() { DeclarationScope* Scope::GetReceiverScope() {
Scope* scope = this; Scope* scope = this;
while (!scope->is_script_scope() && while (!scope->is_declaration_scope() ||
(!scope->is_function_scope() || (!scope->is_script_scope() &&
scope->AsDeclarationScope()->is_arrow_scope())) { !scope->AsDeclarationScope()->has_this_declaration())) {
scope = scope->outer_scope(); scope = scope->outer_scope();
} }
return scope->AsDeclarationScope(); return scope->AsDeclarationScope();
...@@ -1805,16 +1829,6 @@ template Variable* Scope::Lookup<Scope::kDeserializedScope>( ...@@ -1805,16 +1829,6 @@ template Variable* Scope::Lookup<Scope::kDeserializedScope>(
VariableProxy* proxy, Scope* scope, Scope* outer_scope_end, VariableProxy* proxy, Scope* scope, Scope* outer_scope_end,
Scope* entry_point, bool force_context_allocation); Scope* entry_point, bool force_context_allocation);
namespace {
bool CanBeShadowed(Scope* scope, Variable* var) {
if (var == nullptr) return false;
// "this" can't be shadowed by "eval"-introduced bindings or by "with" scopes.
// TODO(wingo): There are other variables in this category; add them.
return !var->is_this();
}
}; // namespace
Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope, Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope,
Scope* outer_scope_end, Scope* entry_point, Scope* outer_scope_end, Scope* entry_point,
bool force_context_allocation) { bool force_context_allocation) {
...@@ -1827,7 +1841,7 @@ Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope, ...@@ -1827,7 +1841,7 @@ Variable* Scope::LookupWith(VariableProxy* proxy, Scope* scope,
: Lookup<kDeserializedScope>(proxy, scope->outer_scope_, : Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
outer_scope_end, entry_point); outer_scope_end, entry_point);
if (!CanBeShadowed(scope, var)) return var; if (var == nullptr) return var;
// The current scope is a with scope, so the variable binding can not be // The current scope is a with scope, so the variable binding can not be
// statically resolved. However, note that it was necessary to do a lookup // statically resolved. However, note that it was necessary to do a lookup
...@@ -1861,7 +1875,7 @@ Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope, ...@@ -1861,7 +1875,7 @@ Variable* Scope::LookupSloppyEval(VariableProxy* proxy, Scope* scope,
nullptr, force_context_allocation) nullptr, force_context_allocation)
: Lookup<kDeserializedScope>(proxy, scope->outer_scope_, : Lookup<kDeserializedScope>(proxy, scope->outer_scope_,
outer_scope_end, entry); outer_scope_end, entry);
if (!CanBeShadowed(scope, var)) return var; if (var == nullptr) return var;
// A variable binding may have been found in an outer scope, but the current // A variable binding may have been found in an outer scope, but the current
// scope makes a sloppy 'eval' call, so the found variable may not be the // scope makes a sloppy 'eval' call, so the found variable may not be the
...@@ -1951,12 +1965,6 @@ void UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) { ...@@ -1951,12 +1965,6 @@ void UpdateNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) {
return SetNeedsHoleCheck(var, proxy); return SetNeedsHoleCheck(var, proxy);
} }
if (var->is_this()) {
DCHECK(IsDerivedConstructor(scope->GetClosureScope()->function_kind()));
// TODO(littledan): implement 'this' hole check elimination.
return SetNeedsHoleCheck(var, proxy);
}
// We should always have valid source positions. // We should always have valid source positions.
DCHECK_NE(var->initializer_position(), kNoSourcePosition); DCHECK_NE(var->initializer_position(), kNoSourcePosition);
DCHECK_NE(proxy->position(), kNoSourcePosition); DCHECK_NE(proxy->position(), kNoSourcePosition);
...@@ -2039,7 +2047,7 @@ bool Scope::MustAllocate(Variable* var) { ...@@ -2039,7 +2047,7 @@ bool Scope::MustAllocate(Variable* var) {
// Give var a read/write use if there is a chance it might be accessed // Give var a read/write use if there is a chance it might be accessed
// via an eval() call. This is only possible if the variable has a // via an eval() call. This is only possible if the variable has a
// visible name. // visible name.
if ((var->is_this() || !var->raw_name()->IsEmpty()) && if (!var->raw_name()->IsEmpty() &&
(inner_scope_calls_eval_ || is_catch_scope() || is_script_scope())) { (inner_scope_calls_eval_ || is_catch_scope() || is_script_scope())) {
var->set_is_used(); var->set_is_used();
if (inner_scope_calls_eval_) var->set_maybe_assigned(); if (inner_scope_calls_eval_) var->set_maybe_assigned();
......
...@@ -474,6 +474,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -474,6 +474,8 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) {
// Find the innermost outer scope that needs a context. // Find the innermost outer scope that needs a context.
Scope* GetOuterScopeWithContext(); Scope* GetOuterScopeWithContext();
bool HasThisReference() const;
// Analyze() must have been called once to create the ScopeInfo. // Analyze() must have been called once to create the ScopeInfo.
Handle<ScopeInfo> scope_info() const { Handle<ScopeInfo> scope_info() const {
DCHECK(!scope_info_.is_null()); DCHECK(!scope_info_.is_null());
...@@ -754,6 +756,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { ...@@ -754,6 +756,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
return var; return var;
} }
void DeserializeReceiver(AstValueFactory* ast_value_factory);
#ifdef DEBUG #ifdef DEBUG
void set_is_being_lazily_parsed(bool is_being_lazily_parsed) { void set_is_being_lazily_parsed(bool is_being_lazily_parsed) {
is_being_lazily_parsed_ = is_being_lazily_parsed; is_being_lazily_parsed_ = is_being_lazily_parsed;
...@@ -837,17 +841,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { ...@@ -837,17 +841,12 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
// The variable corresponding to the 'this' value. // The variable corresponding to the 'this' value.
Variable* receiver() { Variable* receiver() {
DCHECK(has_this_declaration()); DCHECK(has_this_declaration() || is_script_scope());
DCHECK_NOT_NULL(receiver_); DCHECK_NOT_NULL(receiver_);
return receiver_; return receiver_;
} }
// TODO(wingo): Add a GLOBAL_SCOPE scope type which will lexically allocate bool has_this_declaration() const { return has_this_declaration_; }
// "this" (and no other variable) on the native context. Script scopes then
// will not have a "this" declaration.
bool has_this_declaration() const {
return (is_function_scope() && !is_arrow_scope()) || is_module_scope();
}
// The variable corresponding to the 'new.target' value. // The variable corresponding to the 'new.target' value.
Variable* new_target_var() { return new_target_; } Variable* new_target_var() { return new_target_; }
...@@ -1019,6 +1018,13 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { ...@@ -1019,6 +1018,13 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
return preparse_data_builder_; return preparse_data_builder_;
} }
void set_has_this_reference() { has_this_reference_ = true; }
bool has_this_reference() const { return has_this_reference_; }
void UsesThis() {
set_has_this_reference();
GetReceiverScope()->receiver()->ForceContextAllocation();
}
private: private:
V8_INLINE void AllocateParameter(Variable* var, int index); V8_INLINE void AllocateParameter(Variable* var, int index);
...@@ -1055,12 +1061,14 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { ...@@ -1055,12 +1061,14 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
bool is_skipped_function_ : 1; bool is_skipped_function_ : 1;
bool has_inferred_function_name_ : 1; bool has_inferred_function_name_ : 1;
bool has_checked_syntax_ : 1; bool has_checked_syntax_ : 1;
bool has_this_reference_ : 1;
int num_parameters_ = 0; bool has_this_declaration_ : 1;
// If the scope is a function scope, this is the function kind. // If the scope is a function scope, this is the function kind.
const FunctionKind function_kind_; const FunctionKind function_kind_;
int num_parameters_ = 0;
// Parameter list in source order. // Parameter list in source order.
ZonePtrList<Variable> params_; ZonePtrList<Variable> params_;
// Map of function names to lists of functions defined in sloppy blocks // Map of function names to lists of functions defined in sloppy blocks
......
...@@ -59,7 +59,7 @@ class Variable final : public ZoneObject { ...@@ -59,7 +59,7 @@ class Variable final : public ZoneObject {
return ForceContextAllocationField::decode(bit_field_); return ForceContextAllocationField::decode(bit_field_);
} }
void ForceContextAllocation() { void ForceContextAllocation() {
DCHECK(IsUnallocated() || IsContextSlot() || DCHECK(IsUnallocated() || IsContextSlot() || IsLookupSlot() ||
location() == VariableLocation::MODULE); location() == VariableLocation::MODULE);
bit_field_ = ForceContextAllocationField::update(bit_field_, true); bit_field_ = ForceContextAllocationField::update(bit_field_, true);
} }
......
...@@ -155,6 +155,11 @@ void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) { ...@@ -155,6 +155,11 @@ void ScopeIterator::TryParseAndRetrieveScopes(ScopeIterator::Option option) {
DCHECK(non_locals_.is_null()); DCHECK(non_locals_.is_null());
non_locals_ = info_->literal()->scope()->CollectNonLocals( non_locals_ = info_->literal()->scope()->CollectNonLocals(
isolate_, info_, StringSet::New(isolate_)); isolate_, info_, StringSet::New(isolate_));
if (!closure_scope_->has_this_declaration() &&
closure_scope_->HasThisReference()) {
non_locals_ = StringSet::Add(isolate_, non_locals_,
isolate_->factory()->this_string());
}
} }
CHECK(DeclarationScope::Analyze(info_)); CHECK(DeclarationScope::Analyze(info_));
...@@ -304,7 +309,8 @@ ScopeIterator::ScopeType ScopeIterator::Type() const { ...@@ -304,7 +309,8 @@ ScopeIterator::ScopeType ScopeIterator::Type() const {
switch (current_scope_->scope_type()) { switch (current_scope_->scope_type()) {
case FUNCTION_SCOPE: case FUNCTION_SCOPE:
DCHECK_IMPLIES(current_scope_->NeedsContext(), DCHECK_IMPLIES(current_scope_->NeedsContext(),
context_->IsFunctionContext()); context_->IsFunctionContext() ||
context_->IsDebugEvaluateContext());
return ScopeTypeLocal; return ScopeTypeLocal;
case MODULE_SCOPE: case MODULE_SCOPE:
DCHECK_IMPLIES(current_scope_->NeedsContext(), DCHECK_IMPLIES(current_scope_->NeedsContext(),
...@@ -316,9 +322,8 @@ ScopeIterator::ScopeType ScopeIterator::Type() const { ...@@ -316,9 +322,8 @@ ScopeIterator::ScopeType ScopeIterator::Type() const {
context_->IsScriptContext() || context_->IsNativeContext()); context_->IsScriptContext() || context_->IsNativeContext());
return ScopeTypeScript; return ScopeTypeScript;
case WITH_SCOPE: case WITH_SCOPE:
DCHECK_IMPLIES( DCHECK_IMPLIES(current_scope_->NeedsContext(),
current_scope_->NeedsContext(), context_->IsWithContext());
context_->IsWithContext() || context_->IsDebugEvaluateContext());
return ScopeTypeWith; return ScopeTypeWith;
case CATCH_SCOPE: case CATCH_SCOPE:
DCHECK(context_->IsCatchContext()); DCHECK(context_->IsCatchContext());
...@@ -340,7 +345,8 @@ ScopeIterator::ScopeType ScopeIterator::Type() const { ...@@ -340,7 +345,8 @@ ScopeIterator::ScopeType ScopeIterator::Type() const {
// fake it. // fake it.
return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript; return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
} }
if (context_->IsFunctionContext() || context_->IsEvalContext()) { if (context_->IsFunctionContext() || context_->IsEvalContext() ||
context_->IsDebugEvaluateContext()) {
return ScopeTypeClosure; return ScopeTypeClosure;
} }
if (context_->IsCatchContext()) { if (context_->IsCatchContext()) {
...@@ -355,7 +361,7 @@ ScopeIterator::ScopeType ScopeIterator::Type() const { ...@@ -355,7 +361,7 @@ ScopeIterator::ScopeType ScopeIterator::Type() const {
if (context_->IsScriptContext()) { if (context_->IsScriptContext()) {
return ScopeTypeScript; return ScopeTypeScript;
} }
DCHECK(context_->IsWithContext() || context_->IsDebugEvaluateContext()); DCHECK(context_->IsWithContext());
return ScopeTypeWith; return ScopeTypeWith;
} }
...@@ -605,15 +611,20 @@ bool ScopeIterator::VisitContextLocals(const Visitor& visitor, ...@@ -605,15 +611,20 @@ bool ScopeIterator::VisitContextLocals(const Visitor& visitor,
} }
bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode) const { bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode) const {
for (Variable* var : *current_scope_->locals()) { if (mode == Mode::STACK && current_scope_->is_declaration_scope() &&
if (var->is_this()) { current_scope_->AsDeclarationScope()->has_this_declaration()) {
// Only collect "this" for DebugEvaluate. The debugger will manually add Handle<Object> receiver = frame_inspector_ == nullptr
// "this" in a different way, and if we'd add it here as well, it shows up ? handle(generator_->receiver(), isolate_)
// twice. : frame_inspector_->GetReceiver();
if (mode == Mode::ALL) continue; if (receiver->IsOptimizedOut(isolate_) || receiver->IsTheHole(isolate_)) {
} else if (ScopeInfo::VariableIsSynthetic(*var->name())) { receiver = isolate_->factory()->undefined_value();
continue;
} }
if (visitor(isolate_->factory()->this_string(), receiver)) return true;
}
for (Variable* var : *current_scope_->locals()) {
DCHECK(!var->is_this());
if (ScopeInfo::VariableIsSynthetic(*var->name())) continue;
int index = var->index(); int index = var->index();
Handle<Object> value; Handle<Object> value;
...@@ -623,31 +634,21 @@ bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode) const { ...@@ -623,31 +634,21 @@ bool ScopeIterator::VisitLocals(const Visitor& visitor, Mode mode) const {
break; break;
case VariableLocation::UNALLOCATED: case VariableLocation::UNALLOCATED:
if (!var->is_this()) continue; continue;
// No idea why this diverges...
value = frame_inspector_->GetReceiver();
break;
case VariableLocation::PARAMETER: { case VariableLocation::PARAMETER: {
if (frame_inspector_ == nullptr) { if (frame_inspector_ == nullptr) {
// Get the variable from the suspended generator. // Get the variable from the suspended generator.
DCHECK(!generator_.is_null()); DCHECK(!generator_.is_null());
if (var->is_this()) { FixedArray parameters_and_registers =
value = handle(generator_->receiver(), isolate_); generator_->parameters_and_registers();
} else { DCHECK_LT(index, parameters_and_registers->length());
FixedArray parameters_and_registers = value = handle(parameters_and_registers->get(index), isolate_);
generator_->parameters_and_registers();
DCHECK_LT(index, parameters_and_registers->length());
value = handle(parameters_and_registers->get(index), isolate_);
}
} else { } else {
value = var->is_this() ? frame_inspector_->GetReceiver() value = frame_inspector_->GetParameter(index);
: frame_inspector_->GetParameter(index);
if (value->IsOptimizedOut(isolate_)) { if (value->IsOptimizedOut(isolate_)) {
value = isolate_->factory()->undefined_value(); value = isolate_->factory()->undefined_value();
} else if (var->is_this() && value->IsTheHole(isolate_)) {
value = isolate_->factory()->undefined_value();
} }
} }
break; break;
...@@ -727,7 +728,7 @@ void ScopeIterator::VisitLocalScope(const Visitor& visitor, Mode mode) const { ...@@ -727,7 +728,7 @@ void ScopeIterator::VisitLocalScope(const Visitor& visitor, Mode mode) const {
// but don't force |this| to be context-allocated. Otherwise we'd find the // but don't force |this| to be context-allocated. Otherwise we'd find the
// wrong |this| value. // wrong |this| value.
if (!closure_scope_->has_this_declaration() && if (!closure_scope_->has_this_declaration() &&
!non_locals_->Has(isolate_, isolate_->factory()->this_string())) { !closure_scope_->HasThisReference()) {
if (visitor(isolate_->factory()->this_string(), if (visitor(isolate_->factory()->this_string(),
isolate_->factory()->undefined_value())) isolate_->factory()->undefined_value()))
return; return;
......
...@@ -3108,7 +3108,8 @@ BytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs( ...@@ -3108,7 +3108,8 @@ BytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs(
register_allocator()->NewRegisterList(4); register_allocator()->NewRegisterList(4);
SuperPropertyReference* super_property = SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference(); property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), super_property_args[0]); BuildThisAccess();
builder()->StoreAccumulatorInRegister(super_property_args[0]);
VisitForRegisterValue(super_property->home_object(), VisitForRegisterValue(super_property->home_object(),
super_property_args[1]); super_property_args[1]);
builder() builder()
...@@ -3122,7 +3123,8 @@ BytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs( ...@@ -3122,7 +3123,8 @@ BytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs(
register_allocator()->NewRegisterList(4); register_allocator()->NewRegisterList(4);
SuperPropertyReference* super_property = SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference(); property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), super_property_args[0]); BuildThisAccess();
builder()->StoreAccumulatorInRegister(super_property_args[0]);
VisitForRegisterValue(super_property->home_object(), VisitForRegisterValue(super_property->home_object(),
super_property_args[1]); super_property_args[1]);
VisitForRegisterValue(property->key(), super_property_args[2]); VisitForRegisterValue(property->key(), super_property_args[2]);
...@@ -4165,7 +4167,8 @@ void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property, ...@@ -4165,7 +4167,8 @@ void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property,
SuperPropertyReference* super_property = SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference(); property->obj()->AsSuperPropertyReference();
RegisterList args = register_allocator()->NewRegisterList(3); RegisterList args = register_allocator()->NewRegisterList(3);
VisitForRegisterValue(super_property->this_var(), args[0]); BuildThisAccess();
builder()->StoreAccumulatorInRegister(args[0]);
VisitForRegisterValue(super_property->home_object(), args[1]); VisitForRegisterValue(super_property->home_object(), args[1]);
builder()->SetExpressionPosition(property); builder()->SetExpressionPosition(property);
...@@ -4185,7 +4188,8 @@ void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property, ...@@ -4185,7 +4188,8 @@ void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property,
SuperPropertyReference* super_property = SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference(); property->obj()->AsSuperPropertyReference();
RegisterList args = register_allocator()->NewRegisterList(3); RegisterList args = register_allocator()->NewRegisterList(3);
VisitForRegisterValue(super_property->this_var(), args[0]); BuildThisAccess();
builder()->StoreAccumulatorInRegister(args[0]);
VisitForRegisterValue(super_property->home_object(), args[1]); VisitForRegisterValue(super_property->home_object(), args[1]);
VisitForRegisterValue(property->key(), args[2]); VisitForRegisterValue(property->key(), args[2]);
...@@ -4453,8 +4457,8 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { ...@@ -4453,8 +4457,8 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
// Default constructors don't need have to do the assignment because // Default constructors don't need have to do the assignment because
// 'this' isn't accessed in default constructors. // 'this' isn't accessed in default constructors.
if (!IsDefaultConstructor(info()->literal()->kind())) { if (!IsDefaultConstructor(info()->literal()->kind())) {
BuildVariableAssignment(super->this_var()->var(), Token::INIT, Variable* var = closure_scope()->GetReceiverScope()->receiver();
HoleCheckMode::kRequired); BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kRequired);
} }
// The derived constructor has the correct bit set always, so we // The derived constructor has the correct bit set always, so we
...@@ -4584,7 +4588,7 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* unary) { ...@@ -4584,7 +4588,7 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* unary) {
Register object = VisitForRegisterValue(property->obj()); Register object = VisitForRegisterValue(property->obj());
VisitForAccumulatorValue(property->key()); VisitForAccumulatorValue(property->key());
builder()->Delete(object, language_mode()); builder()->Delete(object, language_mode());
} else if (expr->IsVariableProxy() && !expr->AsVariableProxy()->is_this() && } else if (expr->IsVariableProxy() &&
!expr->AsVariableProxy()->is_new_target()) { !expr->AsVariableProxy()->is_new_target()) {
// Delete of an unqualified identifier is allowed in sloppy mode but is // Delete of an unqualified identifier is allowed in sloppy mode but is
// not allowed in strict mode. // not allowed in strict mode.
...@@ -4667,7 +4671,8 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -4667,7 +4671,8 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
RegisterList load_super_args = super_property_args.Truncate(3); RegisterList load_super_args = super_property_args.Truncate(3);
SuperPropertyReference* super_property = SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference(); property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), load_super_args[0]); BuildThisAccess();
builder()->StoreAccumulatorInRegister(load_super_args[0]);
VisitForRegisterValue(super_property->home_object(), load_super_args[1]); VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
builder() builder()
->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
...@@ -4680,7 +4685,8 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -4680,7 +4685,8 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
RegisterList load_super_args = super_property_args.Truncate(3); RegisterList load_super_args = super_property_args.Truncate(3);
SuperPropertyReference* super_property = SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference(); property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), load_super_args[0]); BuildThisAccess();
builder()->StoreAccumulatorInRegister(load_super_args[0]);
VisitForRegisterValue(super_property->home_object(), load_super_args[1]); VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
VisitForRegisterValue(property->key(), load_super_args[2]); VisitForRegisterValue(property->key(), load_super_args[2]);
builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args); builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args);
...@@ -5134,8 +5140,19 @@ void BytecodeGenerator::VisitTemplateLiteral(TemplateLiteral* expr) { ...@@ -5134,8 +5140,19 @@ void BytecodeGenerator::VisitTemplateLiteral(TemplateLiteral* expr) {
} }
} }
void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) { void BytecodeGenerator::BuildThisAccess() {
builder()->LoadAccumulatorWithRegister(Register::function_closure()); DeclarationScope* receiver_scope = closure_scope()->GetReceiverScope();
Variable* var = receiver_scope->receiver();
// TODO(littledan): implement 'this' hole check elimination.
HoleCheckMode hole_check_mode =
IsDerivedConstructor(receiver_scope->function_kind())
? HoleCheckMode::kRequired
: HoleCheckMode::kElided;
BuildVariableLoad(var, hole_check_mode);
}
void BytecodeGenerator::VisitThisExpression(ThisExpression* expr) {
BuildThisAccess();
} }
void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) { void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
......
...@@ -204,6 +204,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -204,6 +204,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildAssignment(const AssignmentLhsData& data, Token::Value op, void BuildAssignment(const AssignmentLhsData& data, Token::Value op,
LookupHoistingMode lookup_hoisting_mode); LookupHoistingMode lookup_hoisting_mode);
void BuildThisAccess();
Expression* GetDestructuringDefaultValue(Expression** target); Expression* GetDestructuringDefaultValue(Expression** target);
void BuildDestructuringArrayAssignment( void BuildDestructuringArrayAssignment(
ArrayLiteral* pattern, Token::Value op, ArrayLiteral* pattern, Token::Value op,
......
...@@ -80,11 +80,6 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, ...@@ -80,11 +80,6 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
break; break;
} }
} }
DCHECK(module_vars_count == 0 || scope->is_module_scope());
// Make sure we allocate the correct amount.
DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
// Determine use and location of the "this" binding if it is present. // Determine use and location of the "this" binding if it is present.
VariableAllocationInfo receiver_info; VariableAllocationInfo receiver_info;
if (scope->is_declaration_scope() && if (scope->is_declaration_scope() &&
...@@ -94,6 +89,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, ...@@ -94,6 +89,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
receiver_info = UNUSED; receiver_info = UNUSED;
} else if (var->IsContextSlot()) { } else if (var->IsContextSlot()) {
receiver_info = CONTEXT; receiver_info = CONTEXT;
context_local_count++;
} else { } else {
DCHECK(var->IsParameter()); DCHECK(var->IsParameter());
receiver_info = STACK; receiver_info = STACK;
...@@ -102,6 +98,11 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, ...@@ -102,6 +98,11 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
receiver_info = NONE; receiver_info = NONE;
} }
DCHECK(module_vars_count == 0 || scope->is_module_scope());
// Make sure we allocate the correct amount.
DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
const bool has_new_target = const bool has_new_target =
scope->is_declaration_scope() && scope->is_declaration_scope() &&
scope->AsDeclarationScope()->new_target_var() != nullptr; scope->AsDeclarationScope()->new_target_var() != nullptr;
...@@ -256,6 +257,22 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope, ...@@ -256,6 +257,22 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
info = ParameterNumberField::update(info, i); info = ParameterNumberField::update(info, i);
scope_info->set(info_index, Smi::FromInt(info)); scope_info->set(info_index, Smi::FromInt(info));
} }
// TODO(verwaest): Remove this unnecessary entry.
if (scope->AsDeclarationScope()->has_this_declaration()) {
Variable* var = scope->AsDeclarationScope()->receiver();
if (var->location() == VariableLocation::CONTEXT) {
int local_index = var->index() - Context::MIN_CONTEXT_SLOTS;
uint32_t info =
VariableModeField::encode(var->mode()) |
InitFlagField::encode(var->initialization_flag()) |
MaybeAssignedFlagField::encode(var->maybe_assigned()) |
ParameterNumberField::encode(ParameterNumberField::kMax);
scope_info->set(context_local_base + local_index, *var->name(), mode);
scope_info->set(context_local_info_base + local_index,
Smi::FromInt(info));
}
}
} }
index += 2 * context_local_count; index += 2 * context_local_count;
......
...@@ -108,6 +108,16 @@ class ExpressionScope { ...@@ -108,6 +108,16 @@ class ExpressionScope {
Report(loc, message); Report(loc, message);
} }
void RecordThisUse() {
ExpressionScope* scope = this;
do {
if (scope->IsArrowHeadParsingScope()) {
scope->AsArrowHeadParsingScope()->RecordThisUse();
}
scope = scope->parent();
} while (scope != nullptr);
}
void RecordPatternError(const Scanner::Location& loc, void RecordPatternError(const Scanner::Location& loc,
MessageTemplate message) { MessageTemplate message) {
// TODO(verwaest): Non-assigning expression? // TODO(verwaest): Non-assigning expression?
...@@ -694,6 +704,7 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> { ...@@ -694,6 +704,7 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
for (auto declaration : *result->declarations()) { for (auto declaration : *result->declarations()) {
declaration->var()->set_initializer_position(initializer_position); declaration->var()->set_initializer_position(initializer_position);
} }
if (uses_this_) result->UsesThis();
return result; return result;
} }
...@@ -705,6 +716,7 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> { ...@@ -705,6 +716,7 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
} }
void RecordNonSimpleParameter() { has_simple_parameter_list_ = false; } void RecordNonSimpleParameter() { has_simple_parameter_list_ = false; }
void RecordThisUse() { uses_this_ = true; }
private: private:
FunctionKind kind() const { FunctionKind kind() const {
...@@ -716,6 +728,7 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> { ...@@ -716,6 +728,7 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
Scanner::Location declaration_error_location = Scanner::Location::invalid(); Scanner::Location declaration_error_location = Scanner::Location::invalid();
MessageTemplate declaration_error_message = MessageTemplate::kNone; MessageTemplate declaration_error_message = MessageTemplate::kNone;
bool has_simple_parameter_list_ = true; bool has_simple_parameter_list_ = true;
bool uses_this_ = false;
DISALLOW_COPY_AND_ASSIGN(ArrowHeadParsingScope); DISALLOW_COPY_AND_ASSIGN(ArrowHeadParsingScope);
}; };
......
...@@ -954,6 +954,26 @@ class ParserBase { ...@@ -954,6 +954,26 @@ class ParserBase {
if (is_strict(language_mode)) parameters.ValidateStrictMode(impl()); if (is_strict(language_mode)) parameters.ValidateStrictMode(impl());
} }
// Needs to be called if the reference needs to be available from the current
// point. It causes the receiver to be context allocated if necessary.
// Returns the receiver variable that we're referencing.
V8_INLINE Variable* UseThis() {
DeclarationScope* closure_scope = scope()->GetClosureScope();
DeclarationScope* receiver_scope = closure_scope->GetReceiverScope();
Variable* var = receiver_scope->receiver();
var->set_is_used();
if (closure_scope == receiver_scope) {
// It's possible that we're parsing the head of an arrow function, in
// which case we haven't realized yet that closure_scope !=
// receiver_scope. Mark through the ExpressionScope for now.
expression_scope()->RecordThisUse();
} else {
closure_scope->set_has_this_reference();
var->ForceContextAllocation();
}
return var;
}
V8_INLINE IdentifierT ParseAndClassifyIdentifier(Token::Value token); V8_INLINE IdentifierT ParseAndClassifyIdentifier(Token::Value token);
// Parses an identifier or a strict mode future reserved word. Allows passing // Parses an identifier or a strict mode future reserved word. Allows passing
// in function_kind for the case of parsing the identifier in a function // in function_kind for the case of parsing the identifier in a function
...@@ -1661,7 +1681,7 @@ ParserBase<Impl>::ParsePrimaryExpression() { ...@@ -1661,7 +1681,7 @@ ParserBase<Impl>::ParsePrimaryExpression() {
switch (token) { switch (token) {
case Token::THIS: { case Token::THIS: {
Consume(Token::THIS); Consume(Token::THIS);
return impl()->ThisExpression(beg_pos); return impl()->ThisExpression();
} }
case Token::ASSIGN_DIV: case Token::ASSIGN_DIV:
...@@ -3259,6 +3279,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression( ...@@ -3259,6 +3279,7 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
IsClassConstructor(kind)) { IsClassConstructor(kind)) {
if (Token::IsProperty(peek())) { if (Token::IsProperty(peek())) {
scope->RecordSuperPropertyUsage(); scope->RecordSuperPropertyUsage();
UseThis();
return impl()->NewSuperPropertyReference(pos); return impl()->NewSuperPropertyReference(pos);
} }
// new super() is never allowed. // new super() is never allowed.
...@@ -3266,6 +3287,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression( ...@@ -3266,6 +3287,8 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseSuperExpression(
if (!is_new && peek() == Token::LPAREN && IsDerivedConstructor(kind)) { if (!is_new && peek() == Token::LPAREN && IsDerivedConstructor(kind)) {
// TODO(rossberg): This might not be the correct FunctionState for the // TODO(rossberg): This might not be the correct FunctionState for the
// method here. // method here.
expression_scope()->RecordThisUse();
UseThis()->set_maybe_assigned();
return impl()->NewSuperCallReference(pos); return impl()->NewSuperCallReference(pos);
} }
} }
...@@ -3841,8 +3864,10 @@ void ParserBase<Impl>::ParseFunctionBody( ...@@ -3841,8 +3864,10 @@ void ParserBase<Impl>::ParseFunctionBody(
} }
if (IsDerivedConstructor(kind)) { if (IsDerivedConstructor(kind)) {
ExpressionParsingScope expression_scope(impl());
inner_body.Add(factory()->NewReturnStatement(impl()->ThisExpression(), inner_body.Add(factory()->NewReturnStatement(impl()->ThisExpression(),
kNoSourcePosition)); kNoSourcePosition));
expression_scope.ValidateExpression();
} }
Expect(closing_token); Expect(closing_token);
} }
...@@ -4982,7 +5007,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement() { ...@@ -4982,7 +5007,9 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement() {
ExpressionT return_value = impl()->NullExpression(); ExpressionT return_value = impl()->NullExpression();
if (scanner()->HasLineTerminatorBeforeNext() || Token::IsAutoSemicolon(tok)) { if (scanner()->HasLineTerminatorBeforeNext() || Token::IsAutoSemicolon(tok)) {
if (IsDerivedConstructor(function_state_->kind())) { if (IsDerivedConstructor(function_state_->kind())) {
return_value = impl()->ThisExpression(loc.beg_pos); ExpressionParsingScope expression_scope(impl());
return_value = impl()->ThisExpression();
expression_scope.ValidateExpression();
} }
} else { } else {
return_value = ParseExpression(); return_value = ParseExpression();
......
...@@ -285,8 +285,7 @@ Expression* Parser::NewSuperPropertyReference(int pos) { ...@@ -285,8 +285,7 @@ Expression* Parser::NewSuperPropertyReference(int pos) {
AstSymbol::kHomeObjectSymbol, kNoSourcePosition); AstSymbol::kHomeObjectSymbol, kNoSourcePosition);
Expression* home_object = factory()->NewProperty( Expression* home_object = factory()->NewProperty(
this_function_proxy, home_object_symbol_literal, pos); this_function_proxy, home_object_symbol_literal, pos);
return factory()->NewSuperPropertyReference( return factory()->NewSuperPropertyReference(home_object, pos);
ThisExpression(pos)->AsVariableProxy(), home_object, pos);
} }
Expression* Parser::NewSuperCallReference(int pos) { Expression* Parser::NewSuperCallReference(int pos) {
...@@ -294,9 +293,8 @@ Expression* Parser::NewSuperCallReference(int pos) { ...@@ -294,9 +293,8 @@ Expression* Parser::NewSuperCallReference(int pos) {
NewUnresolved(ast_value_factory()->new_target_string(), pos); NewUnresolved(ast_value_factory()->new_target_string(), pos);
VariableProxy* this_function_proxy = VariableProxy* this_function_proxy =
NewUnresolved(ast_value_factory()->this_function_string(), pos); NewUnresolved(ast_value_factory()->this_function_string(), pos);
return factory()->NewSuperCallReference( return factory()->NewSuperCallReference(new_target_proxy, this_function_proxy,
ThisExpression(pos)->AsVariableProxy(), new_target_proxy, pos);
this_function_proxy, pos);
} }
Expression* Parser::NewTargetExpression(int pos) { Expression* Parser::NewTargetExpression(int pos) {
...@@ -451,6 +449,10 @@ void Parser::DeserializeScopeChain( ...@@ -451,6 +449,10 @@ void Parser::DeserializeScopeChain(
original_scope_ = Scope::DeserializeScopeChain( original_scope_ = Scope::DeserializeScopeChain(
isolate, zone(), *outer_scope_info, info->script_scope(), isolate, zone(), *outer_scope_info, info->script_scope(),
ast_value_factory(), mode); ast_value_factory(), mode);
if (info->is_eval() || IsArrowFunction(info->function_kind())) {
original_scope_->GetReceiverScope()->DeserializeReceiver(
ast_value_factory());
}
} }
} }
...@@ -1568,8 +1570,11 @@ Expression* Parser::RewriteReturn(Expression* return_value, int pos) { ...@@ -1568,8 +1570,11 @@ Expression* Parser::RewriteReturn(Expression* return_value, int pos) {
factory()->NewUndefinedLiteral(kNoSourcePosition), pos); factory()->NewUndefinedLiteral(kNoSourcePosition), pos);
// is_undefined ? this : temp // is_undefined ? this : temp
// We don't need to call UseThis() since it's guaranteed to be called
// for derived constructors after parsing the constructor in
// ParseFunctionBody.
return_value = return_value =
factory()->NewConditional(is_undefined, ThisExpression(pos), factory()->NewConditional(is_undefined, factory()->ThisExpression(),
factory()->NewVariableProxy(temp), pos); factory()->NewVariableProxy(temp), pos);
} }
return return_value; return return_value;
...@@ -3119,7 +3124,7 @@ Expression* Parser::SpreadCall(Expression* function, ...@@ -3119,7 +3124,7 @@ Expression* Parser::SpreadCall(Expression* function,
if (function->IsProperty()) { if (function->IsProperty()) {
// Method calls // Method calls
if (function->AsProperty()->IsSuperAccess()) { if (function->AsProperty()->IsSuperAccess()) {
Expression* home = ThisExpression(kNoSourcePosition); Expression* home = ThisExpression();
args.Add(function); args.Add(function);
args.Add(home); args.Add(home);
} else { } else {
......
...@@ -565,8 +565,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -565,8 +565,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
V8_INLINE static bool IsThisProperty(Expression* expression) { V8_INLINE static bool IsThisProperty(Expression* expression) {
DCHECK_NOT_NULL(expression); DCHECK_NOT_NULL(expression);
Property* property = expression->AsProperty(); Property* property = expression->AsProperty();
return property != nullptr && property->obj()->IsVariableProxy() && return property != nullptr && property->obj()->IsThisExpression();
property->obj()->AsVariableProxy()->is_this();
} }
// This returns true if the expression is an indentifier (wrapped // This returns true if the expression is an indentifier (wrapped
...@@ -574,8 +573,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -574,8 +573,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
// has been converted to a variable proxy. // has been converted to a variable proxy.
V8_INLINE static bool IsIdentifier(Expression* expression) { V8_INLINE static bool IsIdentifier(Expression* expression) {
VariableProxy* operand = expression->AsVariableProxy(); VariableProxy* operand = expression->AsVariableProxy();
return operand != nullptr && !operand->is_this() && return operand != nullptr && !operand->is_new_target();
!operand->is_new_target();
} }
V8_INLINE static const AstRawString* AsIdentifier(Expression* expression) { V8_INLINE static const AstRawString* AsIdentifier(Expression* expression) {
...@@ -790,9 +788,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -790,9 +788,9 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
return ast_value_factory()->GetOneByteString(string); return ast_value_factory()->GetOneByteString(string);
} }
V8_INLINE Expression* ThisExpression(int pos = kNoSourcePosition) { class ThisExpression* ThisExpression() {
return NewUnresolved(ast_value_factory()->this_string(), pos, UseThis();
THIS_VARIABLE); return factory()->ThisExpression();
} }
Expression* NewSuperPropertyReference(int pos); Expression* NewSuperPropertyReference(int pos);
......
...@@ -1537,10 +1537,8 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1537,10 +1537,8 @@ class PreParser : public ParserBase<PreParser> {
return PreParserIdentifier::Default(); return PreParserIdentifier::Default();
} }
V8_INLINE PreParserExpression ThisExpression(int pos = kNoSourcePosition) { V8_INLINE PreParserExpression ThisExpression() {
scope()->NewUnresolved(factory()->ast_node_factory(), UseThis();
ast_value_factory()->this_string(), pos,
THIS_VARIABLE);
return PreParserExpression::This(); return PreParserExpression::This();
} }
...@@ -1548,9 +1546,6 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1548,9 +1546,6 @@ class PreParser : public ParserBase<PreParser> {
scope()->NewUnresolved(factory()->ast_node_factory(), scope()->NewUnresolved(factory()->ast_node_factory(),
ast_value_factory()->this_function_string(), pos, ast_value_factory()->this_function_string(), pos,
NORMAL_VARIABLE); NORMAL_VARIABLE);
scope()->NewUnresolved(factory()->ast_node_factory(),
ast_value_factory()->this_string(), pos,
THIS_VARIABLE);
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
...@@ -1561,9 +1556,6 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1561,9 +1556,6 @@ class PreParser : public ParserBase<PreParser> {
scope()->NewUnresolved(factory()->ast_node_factory(), scope()->NewUnresolved(factory()->ast_node_factory(),
ast_value_factory()->new_target_string(), pos, ast_value_factory()->new_target_string(), pos,
NORMAL_VARIABLE); NORMAL_VARIABLE);
scope()->NewUnresolved(factory()->ast_node_factory(),
ast_value_factory()->this_string(), pos,
THIS_VARIABLE);
return PreParserExpression::SuperCallReference(); return PreParserExpression::SuperCallReference();
} }
......
...@@ -1101,8 +1101,7 @@ TEST(ScopeUsesArgumentsSuperThis) { ...@@ -1101,8 +1101,7 @@ TEST(ScopeUsesArgumentsSuperThis) {
if ((source_data[i].expected & THIS) != 0) { if ((source_data[i].expected & THIS) != 0) {
// Currently the is_used() flag is conservative; all variables in a // Currently the is_used() flag is conservative; all variables in a
// script scope are marked as used. // script scope are marked as used.
CHECK(scope->LookupForTesting(info.ast_value_factory()->this_string()) CHECK(scope->GetReceiverScope()->receiver()->is_used());
->is_used());
} }
if (is_sloppy(scope->language_mode())) { if (is_sloppy(scope->language_mode())) {
CHECK_EQ((source_data[i].expected & EVAL) != 0, CHECK_EQ((source_data[i].expected & EVAL) != 0,
......
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