Version 5.2.361.25 (cherry-pick)

Merged 0e14baf712955a1993f742647bb2adc293702b80

Rewrite scopes of non-simple default arguments

BUG=chromium:616386
LOG=N
R=littledan@chromium.org

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

Cr-Commit-Position: refs/branch-heads/5.2@{#31}
Cr-Branched-From: 2cd36d6d0439ddfbe84cd90e112dced85084ec95-refs/heads/5.2.361@{#1}
Cr-Branched-From: 3fef34e02388e07d46067c516320f1ff12304c8e-refs/heads/master@{#36332}
diff --git a/include/v8-version.h b/include/v8-version.h
index 15074fb..777cd2c 100644
--- a/include/v8-version.h
+++ b/include/v8-version.h
@@ -11,7 +11,7 @@
 #define V8_MAJOR_VERSION 5
 #define V8_MINOR_VERSION 2
 #define V8_BUILD_NUMBER 361
-#define V8_PATCH_LEVEL 24
+#define V8_PATCH_LEVEL 25
 
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/parsing/parameter-initializer-rewriter.cc b/src/parsing/parameter-initializer-rewriter.cc
index cbbf8de..6362c63 100644
--- a/src/parsing/parameter-initializer-rewriter.cc
+++ b/src/parsing/parameter-initializer-rewriter.cc
@@ -90,6 +90,10 @@
   if (proxy->is_resolved()) {
     Variable* var = proxy->var();
     if (var->mode() != TEMPORARY) return;
+    // For rewriting inside the same ClosureScope (e.g., putting default
+    // parameter values in their own inner scope in certain cases), refrain
+    // from invalidly moving temporaries to a block scope.
+    if (var->scope()->ClosureScope() == new_scope_->ClosureScope()) return;
     int index = old_scope_->RemoveTemporary(var);
     if (index >= 0) {
       temps_.push_back(std::make_pair(var, index));
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index b4e4176..1f267d3 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -4583,6 +4583,12 @@
       param_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition);
       param_block->set_scope(param_scope);
       descriptor.hoist_scope = scope_;
+      // Pass the appropriate scope in so that PatternRewriter can appropriately
+      // rewrite inner initializers of the pattern to param_scope
+      descriptor.scope = param_scope;
+      // Rewrite the outer initializer to point to param_scope
+      RewriteParameterInitializerScope(stack_limit(), initial_value, scope_,
+                                       param_scope);
     }
 
     {
diff --git a/src/parsing/pattern-rewriter.cc b/src/parsing/pattern-rewriter.cc
index 91d7549..808c0c0 100644
--- a/src/parsing/pattern-rewriter.cc
+++ b/src/parsing/pattern-rewriter.cc
@@ -677,9 +677,29 @@
                                       RelocInfo::kNoPosition);
   }
 
+  // Two cases for scope rewriting the scope of default parameters:
+  // - Eagerly parsed arrow functions are initially parsed as having
+  //   initializers in the enclosing scope, but when the arrow is encountered,
+  //   need to be in the scope of the function.
+  // - When an extra declaration scope needs to be inserted to account for
+  //   a sloppy eval in a default parameter or function body, the initializer
+  //   needs to be in that new inner scope which was added after initial
+  //   parsing.
+  // Each of these cases can be handled by rewriting the contents of the
+  // initializer to the current scope. The source scope is typically the outer
+  // scope when one case occurs; when both cases occur, both scopes need to
+  // be included as the outer scope. (Both rewritings still need to be done
+  // to account for lazily parsed arrow functions which hit the second case.)
+  // TODO(littledan): Remove the outer_scope parameter of
+  //                  RewriteParameterInitializerScope
   if (IsBindingContext() &&
       descriptor_->declaration_kind == DeclarationDescriptor::PARAMETER &&
-      scope()->is_arrow_scope()) {
+      (scope()->is_arrow_scope() || scope()->is_block_scope())) {
+    if (scope()->outer_scope()->is_arrow_scope() && scope()->is_block_scope()) {
+      RewriteParameterInitializerScope(parser_->stack_limit(), initializer,
+                                       scope()->outer_scope()->outer_scope(),
+                                       scope());
+    }
     RewriteParameterInitializerScope(parser_->stack_limit(), initializer,
                                      scope()->outer_scope(), scope());
   }
diff --git a/test/mjsunit/regress/regress-616386.js b/test/mjsunit/regress/regress-616386.js
new file mode 100644
index 0000000..d462ab7
--- /dev/null
+++ b/test/mjsunit/regress/regress-616386.js
@@ -0,0 +1,10 @@
+// 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
+
+assertEquals(0, ((y = (function(a2) { bbbb = a2 }), bbbb = eval('1')) => {y(0); return bbbb})())
+assertEquals(0, (({y = (function(a2) { bbbb = a2 }), bbbb = eval('1')} = {}) => {y(0); return bbbb})())
+assertEquals(0, (function (y = (function(a2) { bbbb = a2 }), bbbb = eval('1')) {y(0); return bbbb})())
+assertEquals(0, (function ({y = (function(a2) { bbbb = a2 }), bbbb = eval('1')} = {}) {y(0); return bbbb})())