Commit 0406fa22 authored by nikolaos's avatar nikolaos Committed by Commit bot

Fix for temporaries in parameter initializers

This patch introduces a mechanism for changing the scope of temporary
variables, which is necessary for rewriting arrow parameter
initializers.

It also fixes a potential bug in AstExpressionVisitor, which did not
visit the automatically generated members of ForEachStatement.

Fixes test/mjsunit/harmony/regress/regress-4658.js

R=rossberg@chromium.org
BUG=v8:4658
LOG=N

Review URL: https://codereview.chromium.org/1564343002

Cr-Commit-Position: refs/heads/master@{#33183}
parent e375ceac
...@@ -171,6 +171,11 @@ void AstExpressionVisitor::VisitForInStatement(ForInStatement* stmt) { ...@@ -171,6 +171,11 @@ void AstExpressionVisitor::VisitForInStatement(ForInStatement* stmt) {
void AstExpressionVisitor::VisitForOfStatement(ForOfStatement* stmt) { void AstExpressionVisitor::VisitForOfStatement(ForOfStatement* stmt) {
RECURSE(Visit(stmt->iterable())); RECURSE(Visit(stmt->iterable()));
RECURSE(Visit(stmt->each()));
RECURSE(Visit(stmt->assign_iterator()));
RECURSE(Visit(stmt->next_result()));
RECURSE(Visit(stmt->result_done()));
RECURSE(Visit(stmt->assign_each()));
RECURSE(Visit(stmt->body())); RECURSE(Visit(stmt->body()));
} }
......
...@@ -575,11 +575,24 @@ Variable* Scope::NewTemporary(const AstRawString* name) { ...@@ -575,11 +575,24 @@ Variable* Scope::NewTemporary(const AstRawString* name) {
TEMPORARY, TEMPORARY,
Variable::NORMAL, Variable::NORMAL,
kCreatedInitialized); kCreatedInitialized);
scope->temps_.Add(var, zone()); scope->AddTemporary(var);
return var; return var;
} }
bool Scope::RemoveTemporary(Variable* var) {
// Most likely (always?) any temporary variable we want to remove
// was just added before, so we search backwards.
for (int i = temps_.length(); i-- > 0;) {
if (temps_[i] == var) {
temps_.Remove(i);
return true;
}
}
return false;
}
void Scope::AddDeclaration(Declaration* declaration) { void Scope::AddDeclaration(Declaration* declaration) {
decls_.Add(declaration, zone()); decls_.Add(declaration, zone());
} }
......
...@@ -209,6 +209,15 @@ class Scope: public ZoneObject { ...@@ -209,6 +209,15 @@ class Scope: public ZoneObject {
// names. // names.
Variable* NewTemporary(const AstRawString* name); Variable* NewTemporary(const AstRawString* name);
// Remove a temporary variable. This is for adjusting the scope of
// temporaries used when desugaring parameter initializers.
bool RemoveTemporary(Variable* var);
// Adds a temporary variable in this scope's TemporaryScope. This is for
// adjusting the scope of temporaries used when desugaring parameter
// initializers.
void AddTemporary(Variable* var) { 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
// the scope; see codegen.cc:ProcessDeclarations. // the scope; see codegen.cc:ProcessDeclarations.
......
...@@ -37,6 +37,10 @@ class Variable: public ZoneObject { ...@@ -37,6 +37,10 @@ class Variable: public ZoneObject {
// scope is only used to follow the context chain length. // scope is only used to follow the context chain length.
Scope* scope() const { return scope_; } Scope* scope() const { return scope_; }
// This is for adjusting the scope of temporaries used when desugaring
// parameter initializers.
void set_scope(Scope* scope) { scope_ = scope; }
Handle<String> name() const { return name_->string(); } Handle<String> name() const { return name_->string(); }
const AstRawString* raw_name() const { return name_; } const AstRawString* raw_name() const { return name_; }
VariableMode mode() const { return mode_; } VariableMode mode() const { return mode_; }
......
...@@ -60,8 +60,14 @@ void Rewriter::VisitClassLiteral(ClassLiteral* class_literal) { ...@@ -60,8 +60,14 @@ void Rewriter::VisitClassLiteral(ClassLiteral* class_literal) {
void Rewriter::VisitVariableProxy(VariableProxy* proxy) { void Rewriter::VisitVariableProxy(VariableProxy* proxy) {
DCHECK(!proxy->is_resolved()); if (proxy->is_resolved()) {
if (old_scope_->RemoveUnresolved(proxy)) { Variable* var = proxy->var();
DCHECK_EQ(var->mode(), TEMPORARY);
if (old_scope_->RemoveTemporary(var)) {
var->set_scope(new_scope_);
new_scope_->AddTemporary(var);
}
} else if (old_scope_->RemoveUnresolved(proxy)) {
new_scope_->AddUnresolved(proxy); new_scope_->AddUnresolved(proxy);
} }
} }
......
// Copyright 2015 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: --harmony-do-expressions
(function testWithSimpleLoopVariable() {
var f = (x, y = (do { var s=0; for (var e of x) s += e; s; })) => y*(y+1);
var result = f([1,2,3]); // core dump here, if not fixed.
assertEquals(result, 42);
})();
(function testWithComplexLoopVariable() {
var f = (x, i=x[0]-1, a=[],
y = (do { var s=0;
for (a[i] of x) s += a[i++];
s;
})) => y*(a[0]+a[1]*a[2]);
var result = f([1,2,3]); // core dump here, if not fixed.
assertEquals(result, 42);
})();
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