Commit 61c137c8 authored by nikolaos's avatar nikolaos Committed by Commit bot

Fix bug with re-scoping arrow function parameter initializers

When re-scoping arrow function parameter initializers, temporaries
should be moved from the closure of the old scope to the closure of
the new scope, if necessary.

R=adamk@chromium.org, rossberg@chromium.org
BUG=chromium:622663
LOG=N

Review-Url: https://codereview.chromium.org/2083083007
Cr-Commit-Position: refs/heads/master@{#37335}
parent 872c461b
...@@ -555,6 +555,11 @@ Variable* Scope::NewTemporary(const AstRawString* name) { ...@@ -555,6 +555,11 @@ Variable* Scope::NewTemporary(const AstRawString* name) {
int Scope::RemoveTemporary(Variable* var) { int Scope::RemoveTemporary(Variable* var) {
DCHECK_NOT_NULL(var); DCHECK_NOT_NULL(var);
// Temporaries are only placed in ClosureScopes.
DCHECK_EQ(ClosureScope(), this);
DCHECK_EQ(var->scope()->ClosureScope(), var->scope());
// If the temporary is not here, return quickly.
if (var->scope() != this) return -1;
// Most likely (always?) any temporary variable we want to remove // Most likely (always?) any temporary variable we want to remove
// was just added before, so we search backwards. // was just added before, so we search backwards.
for (int i = temps_.length(); i-- > 0;) { for (int i = temps_.length(); i-- > 0;) {
......
...@@ -216,7 +216,11 @@ class Scope: public ZoneObject { ...@@ -216,7 +216,11 @@ class Scope: public ZoneObject {
// Adds a temporary variable in this scope's TemporaryScope. This is for // Adds a temporary variable in this scope's TemporaryScope. This is for
// adjusting the scope of temporaries used when desugaring parameter // adjusting the scope of temporaries used when desugaring parameter
// initializers. // initializers.
void AddTemporary(Variable* var) { temps_.Add(var, zone()); } void AddTemporary(Variable* var) {
// Temporaries are only placed in ClosureScopes.
DCHECK_EQ(ClosureScope(), this);
temps_.Add(var, zone());
}
// Adds the specific declaration node to the list of declarations in // Adds the specific declaration node to the list of declarations in
// this scope. The declarations are processed as part of entering // this scope. The declarations are processed as part of entering
......
...@@ -24,7 +24,9 @@ class Rewriter final : public AstExpressionVisitor { ...@@ -24,7 +24,9 @@ class Rewriter final : public AstExpressionVisitor {
Scope* new_scope) Scope* new_scope)
: AstExpressionVisitor(stack_limit, initializer), : AstExpressionVisitor(stack_limit, initializer),
old_scope_(old_scope), old_scope_(old_scope),
new_scope_(new_scope) {} new_scope_(new_scope),
old_scope_closure_(old_scope->ClosureScope()),
new_scope_closure_(new_scope->ClosureScope()) {}
~Rewriter(); ~Rewriter();
private: private:
...@@ -40,6 +42,8 @@ class Rewriter final : public AstExpressionVisitor { ...@@ -40,6 +42,8 @@ class Rewriter final : public AstExpressionVisitor {
Scope* old_scope_; Scope* old_scope_;
Scope* new_scope_; Scope* new_scope_;
Scope* old_scope_closure_;
Scope* new_scope_closure_;
std::vector<std::pair<Variable*, int>> temps_; std::vector<std::pair<Variable*, int>> temps_;
}; };
...@@ -55,8 +59,8 @@ Rewriter::~Rewriter() { ...@@ -55,8 +59,8 @@ Rewriter::~Rewriter() {
// Ensure that we add temporaries in the order they appeared in old_scope_. // Ensure that we add temporaries in the order they appeared in old_scope_.
std::sort(temps_.begin(), temps_.end(), LessThanSecond()); std::sort(temps_.begin(), temps_.end(), LessThanSecond());
for (auto var_and_index : temps_) { for (auto var_and_index : temps_) {
var_and_index.first->set_scope(new_scope_); var_and_index.first->set_scope(new_scope_closure_);
new_scope_->AddTemporary(var_and_index.first); new_scope_closure_->AddTemporary(var_and_index.first);
} }
} }
} }
...@@ -90,11 +94,11 @@ void Rewriter::VisitVariableProxy(VariableProxy* proxy) { ...@@ -90,11 +94,11 @@ void Rewriter::VisitVariableProxy(VariableProxy* proxy) {
if (proxy->is_resolved()) { if (proxy->is_resolved()) {
Variable* var = proxy->var(); Variable* var = proxy->var();
if (var->mode() != TEMPORARY) return; if (var->mode() != TEMPORARY) return;
// For rewriting inside the same ClosureScope (e.g., putting default // Temporaries are only placed in ClosureScopes.
// parameter values in their own inner scope in certain cases), refrain DCHECK_EQ(var->scope(), var->scope()->ClosureScope());
// from invalidly moving temporaries to a block scope. // If the temporary is already where it should be, return quickly.
if (var->scope()->ClosureScope() == new_scope_->ClosureScope()) return; if (var->scope() == new_scope_closure_) return;
int index = old_scope_->RemoveTemporary(var); int index = old_scope_closure_->RemoveTemporary(var);
if (index >= 0) { if (index >= 0) {
temps_.push_back(std::make_pair(var, index)); temps_.push_back(std::make_pair(var, index));
} }
......
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --no-lazy
(function() {
try { (y = [...[]]) => {} } catch(_) {} // will core dump, if not fixed
})();
(function() {
try { ((y = [...[]]) => {})(); } catch(_) {} // will core dump, if not fixed,
// even without --no-lazy
})();
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