Revert "Revert "Upgrade to 5.0.71.48"" DO NOT MERGE

This reverts commit f2e3994fa5148cc3d9946666f0b0596290192b0e,
and updates the x64 makefile properly so it doesn't break that
build.

FPIIM-449

Change-Id: Ib83e35bfbae6af627451c926a9650ec57c045605
(cherry picked from commit 109988c7ccb6f3fd1a58574fa3dfb88beaef6632)
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index b1b8c13..968e8ed 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -6,6 +6,7 @@
 
 #include "src/api.h"
 #include "src/ast/ast.h"
+#include "src/ast/ast-expression-rewriter.h"
 #include "src/ast/ast-expression-visitor.h"
 #include "src/ast/ast-literal-reindexer.h"
 #include "src/ast/scopeinfo.h"
@@ -22,6 +23,7 @@
 #include "src/parsing/scanner-character-streams.h"
 #include "src/runtime/runtime.h"
 #include "src/string-stream.h"
+#include "src/tracing/trace-event.h"
 
 namespace v8 {
 namespace internal {
@@ -178,15 +180,14 @@
   }
 }
 
-
-FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
+FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
+                                            bool call_super, Scope* scope,
                                             int pos, int end_pos,
                                             LanguageMode language_mode) {
   int materialized_literal_count = -1;
   int expected_property_count = -1;
   int parameter_count = 0;
-  const AstRawString* name = ast_value_factory()->empty_string();
-
+  if (name == nullptr) name = ast_value_factory()->empty_string();
 
   FunctionKind kind = call_super ? FunctionKind::kDefaultSubclassConstructor
                                  : FunctionKind::kDefaultBaseConstructor;
@@ -642,10 +643,16 @@
 }
 
 
-Expression* ParserTraits::DefaultConstructor(bool call_super, Scope* scope,
-                                             int pos, int end_pos,
-                                             LanguageMode mode) {
-  return parser_->DefaultConstructor(call_super, scope, pos, end_pos, mode);
+Expression* ParserTraits::FunctionSentExpression(Scope* scope,
+                                                 AstNodeFactory* factory,
+                                                 int pos) {
+  // We desugar function.sent into %GeneratorGetInput(generator).
+  Zone* zone = parser_->zone();
+  ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(1, zone);
+  VariableProxy* generator = factory->NewVariableProxy(
+      parser_->function_state_->generator_object_variable());
+  args->Add(generator, zone);
+  return factory->NewCallRuntime(Runtime::kGeneratorGetInput, args, pos);
 }
 
 
@@ -721,11 +728,10 @@
     const AstRawString* name, Scanner::Location function_name_location,
     FunctionNameValidity function_name_validity, FunctionKind kind,
     int function_token_position, FunctionLiteral::FunctionType type,
-    FunctionLiteral::ArityRestriction arity_restriction,
     LanguageMode language_mode, bool* ok) {
   return parser_->ParseFunctionLiteral(
       name, function_name_location, function_name_validity, kind,
-      function_token_position, type, arity_restriction, language_mode, ok);
+      function_token_position, type, language_mode, ok);
 }
 
 
@@ -767,6 +773,7 @@
   set_allow_legacy_const(FLAG_legacy_const);
   set_allow_harmony_do_expressions(FLAG_harmony_do_expressions);
   set_allow_harmony_function_name(FLAG_harmony_function_name);
+  set_allow_harmony_function_sent(FLAG_harmony_function_sent);
   for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
        ++feature) {
     use_counts_[feature] = 0;
@@ -789,6 +796,7 @@
   DCHECK(parsing_on_main_thread_);
 
   HistogramTimerScope timer_scope(isolate->counters()->parse(), true);
+  TRACE_EVENT0("v8", "V8.Parse");
   Handle<String> source(String::cast(info->script()->source()));
   isolate->counters()->total_parse_size()->Increment(source->length());
   base::ElapsedTimer timer;
@@ -935,13 +943,9 @@
 
     if (ok) {
       ParserTraits::RewriteDestructuringAssignments();
-      result = factory()->NewFunctionLiteral(
-          ast_value_factory()->empty_string(), scope_, body,
-          function_state.materialized_literal_count(),
-          function_state.expected_property_count(), 0,
-          FunctionLiteral::kNoDuplicateParameters,
-          FunctionLiteral::kGlobalOrEval, FunctionLiteral::kShouldLazyCompile,
-          FunctionKind::kNormalFunction, 0);
+      result = factory()->NewScriptOrEvalFunctionLiteral(
+          scope_, body, function_state.materialized_literal_count(),
+          function_state.expected_property_count());
     }
   }
 
@@ -957,6 +961,7 @@
   // called in the main thread.
   DCHECK(parsing_on_main_thread_);
   HistogramTimerScope timer_scope(isolate->counters()->parse_lazy());
+  TRACE_EVENT0("v8", "V8.ParseLazy");
   Handle<String> source(String::cast(info->script()->source()));
   isolate->counters()->total_parse_size()->Increment(source->length());
   base::ElapsedTimer timer;
@@ -990,6 +995,18 @@
   return result;
 }
 
+static FunctionLiteral::FunctionType ComputeFunctionType(
+    Handle<SharedFunctionInfo> shared_info) {
+  if (shared_info->is_declaration()) {
+    return FunctionLiteral::kDeclaration;
+  } else if (shared_info->is_named_expression()) {
+    return FunctionLiteral::kNamedExpression;
+  } else if (IsConciseMethod(shared_info->kind()) ||
+             IsAccessorFunction(shared_info->kind())) {
+    return FunctionLiteral::kAccessorOrMethod;
+  }
+  return FunctionLiteral::kAnonymousExpression;
+}
 
 FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
                                    Utf16CharacterStream* source) {
@@ -1028,11 +1045,7 @@
            is_strict(info->language_mode()));
     DCHECK(info->language_mode() == shared_info->language_mode());
     FunctionLiteral::FunctionType function_type =
-        shared_info->is_expression()
-            ? (shared_info->is_anonymous()
-                   ? FunctionLiteral::kAnonymousExpression
-                   : FunctionLiteral::kNamedExpression)
-            : FunctionLiteral::kDeclaration;
+        ComputeFunctionType(shared_info);
     bool ok = true;
 
     if (shared_info->is_arrow()) {
@@ -1050,7 +1063,7 @@
       SetLanguageMode(scope, shared_info->language_mode());
 
       scope->set_start_position(shared_info->start_position());
-      ExpressionClassifier formals_classifier;
+      ExpressionClassifier formals_classifier(this);
       ParserFormalParameters formals(scope);
       Checkpoint checkpoint(this);
       {
@@ -1096,15 +1109,15 @@
         }
       }
     } else if (shared_info->is_default_constructor()) {
-      result = DefaultConstructor(IsSubclassConstructor(shared_info->kind()),
-                                  scope, shared_info->start_position(),
-                                  shared_info->end_position(),
-                                  shared_info->language_mode());
+      result = DefaultConstructor(
+          raw_name, IsSubclassConstructor(shared_info->kind()), scope,
+          shared_info->start_position(), shared_info->end_position(),
+          shared_info->language_mode());
     } else {
-      result = ParseFunctionLiteral(
-          raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck,
-          shared_info->kind(), RelocInfo::kNoPosition, function_type,
-          FunctionLiteral::kNormalArity, shared_info->language_mode(), &ok);
+      result = ParseFunctionLiteral(raw_name, Scanner::Location::invalid(),
+                                    kSkipFunctionNameCheck, shared_info->kind(),
+                                    RelocInfo::kNoPosition, function_type,
+                                    shared_info->language_mode(), &ok);
     }
     // Make sure the results agree.
     DCHECK(ok == (result != NULL));
@@ -1260,20 +1273,11 @@
   //    Statement
   //    Declaration
 
-  if (peek() != Token::CLASS) {
-    // No more classes follow; reset the start position for the consecutive
-    // class declaration group.
-    scope_->set_class_declaration_group_start(-1);
-  }
-
   switch (peek()) {
     case Token::FUNCTION:
       return ParseFunctionDeclaration(NULL, ok);
     case Token::CLASS:
-      if (scope_->class_declaration_group_start() < 0) {
-        scope_->set_class_declaration_group_start(
-            scanner()->peek_location().beg_pos);
-      }
+      Consume(Token::CLASS);
       return ParseClassDeclaration(NULL, ok);
     case Token::CONST:
       if (allow_const()) {
@@ -1345,7 +1349,6 @@
     }
   }
 
-  scope_->module()->Freeze();
   return NULL;
 }
 
@@ -1558,24 +1561,53 @@
   Expect(Token::DEFAULT, CHECK_OK);
   Scanner::Location default_loc = scanner()->location();
 
+  const AstRawString* default_string = ast_value_factory()->default_string();
   ZoneList<const AstRawString*> names(1, zone());
-  Statement* result = NULL;
+  Statement* result = nullptr;
+  Expression* default_export = nullptr;
   switch (peek()) {
-    case Token::FUNCTION:
-      // TODO(ES6): Support parsing anonymous function declarations here.
-      result = ParseFunctionDeclaration(&names, CHECK_OK);
+    case Token::FUNCTION: {
+      Consume(Token::FUNCTION);
+      int pos = position();
+      bool is_generator = Check(Token::MUL);
+      if (peek() == Token::LPAREN) {
+        // FunctionDeclaration[+Default] ::
+        //   'function' '(' FormalParameters ')' '{' FunctionBody '}'
+        //
+        // GeneratorDeclaration[+Default] ::
+        //   'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
+        default_export = ParseFunctionLiteral(
+            default_string, Scanner::Location::invalid(),
+            kSkipFunctionNameCheck,
+            is_generator ? FunctionKind::kGeneratorFunction
+                         : FunctionKind::kNormalFunction,
+            pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
+        result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+      } else {
+        result = ParseFunctionDeclaration(pos, is_generator, &names, CHECK_OK);
+      }
       break;
+    }
 
     case Token::CLASS:
-      // TODO(ES6): Support parsing anonymous class declarations here.
-      result = ParseClassDeclaration(&names, CHECK_OK);
+      Consume(Token::CLASS);
+      if (peek() == Token::EXTENDS || peek() == Token::LBRACE) {
+        // ClassDeclaration[+Default] ::
+        //   'class' ('extends' LeftHandExpression)? '{' ClassBody '}'
+        default_export =
+            ParseClassLiteral(default_string, Scanner::Location::invalid(),
+                              false, position(), CHECK_OK);
+        result = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+      } else {
+        result = ParseClassDeclaration(&names, CHECK_OK);
+      }
       break;
 
     default: {
       int pos = peek_position();
-      ExpressionClassifier classifier;
+      ExpressionClassifier classifier(this);
       Expression* expr = ParseAssignmentExpression(true, &classifier, CHECK_OK);
-      expr = ParserTraits::RewriteNonPattern(expr, &classifier, CHECK_OK);
+      RewriteNonPattern(&classifier, CHECK_OK);
 
       ExpectSemicolon(CHECK_OK);
       result = factory()->NewExpressionStatement(expr, pos);
@@ -1583,19 +1615,18 @@
     }
   }
 
-  const AstRawString* default_string = ast_value_factory()->default_string();
-
   DCHECK_LE(names.length(), 1);
   if (names.length() == 1) {
     scope_->module()->AddLocalExport(default_string, names.first(), zone(), ok);
     if (!*ok) {
       ParserTraits::ReportMessageAt(
           default_loc, MessageTemplate::kDuplicateExport, default_string);
-      return NULL;
+      return nullptr;
     }
   } else {
     // TODO(ES6): Assign result to a const binding with the name "*default*"
     // and add an export entry with "*default*" as the local name.
+    USE(default_export);
   }
 
   return result;
@@ -1686,6 +1717,7 @@
       break;
 
     case Token::CLASS:
+      Consume(Token::CLASS);
       result = ParseClassDeclaration(&names, CHECK_OK);
       break;
 
@@ -1921,42 +1953,44 @@
     if (var == NULL) {
       // Declare the name.
       Variable::Kind kind = Variable::NORMAL;
-      int declaration_group_start = -1;
       if (is_function_declaration) {
         kind = Variable::FUNCTION;
-      } else if (declaration->IsVariableDeclaration() &&
-                 declaration->AsVariableDeclaration()->is_class_declaration()) {
-        kind = Variable::CLASS;
-        declaration_group_start =
-            declaration->AsVariableDeclaration()->declaration_group_start();
       }
       var = declaration_scope->DeclareLocal(
-          name, mode, declaration->initialization(), kind, kNotAssigned,
-          declaration_group_start);
-    } else if (((IsLexicalVariableMode(mode) ||
-                 IsLexicalVariableMode(var->mode())) &&
-                // Allow duplicate function decls for web compat, see bug 4693.
-                (is_strict(language_mode()) || !is_function_declaration ||
-                 !var->is_function())) ||
-               ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
-                !declaration_scope->is_script_scope())) {
-      // The name was declared in this scope before; check for conflicting
-      // re-declarations. We have a conflict if either of the declarations is
-      // not a var (in script scope, we also have to ignore legacy const for
-      // compatibility). There is similar code in runtime.cc in the Declare
-      // functions. The function CheckConflictingVarDeclarations checks for
-      // var and let bindings from different scopes whereas this is a check for
-      // conflicting declarations within the same scope. This check also covers
-      // the special case
-      //
-      // function () { let x; { var x; } }
-      //
-      // because the var declaration is hoisted to the function scope where 'x'
-      // is already bound.
-      DCHECK(IsDeclaredVariableMode(var->mode()));
-      if (is_strict(language_mode()) ||
-          (allow_harmony_sloppy() && mode != CONST_LEGACY &&
-           var->mode() != CONST_LEGACY)) {
+          name, mode, declaration->initialization(), kind, kNotAssigned);
+    } else if ((mode == CONST_LEGACY || var->mode() == CONST_LEGACY) &&
+               !declaration_scope->is_script_scope()) {
+      // Duplicate legacy const definitions throw at runtime.
+      DCHECK(is_sloppy(language_mode()));
+      Expression* expression = NewThrowSyntaxError(
+          MessageTemplate::kVarRedeclaration, name, declaration->position());
+      declaration_scope->SetIllegalRedeclaration(expression);
+    } else if ((IsLexicalVariableMode(mode) ||
+                IsLexicalVariableMode(var->mode())) &&
+               // Lexical bindings may appear for some parameters in sloppy
+               // mode even with --harmony-sloppy off.
+               (is_strict(language_mode()) || allow_harmony_sloppy())) {
+      // Allow duplicate function decls for web compat, see bug 4693.
+      if (is_sloppy(language_mode()) && is_function_declaration &&
+          var->is_function()) {
+        DCHECK(IsLexicalVariableMode(mode) &&
+               IsLexicalVariableMode(var->mode()));
+        ++use_counts_[v8::Isolate::kSloppyModeBlockScopedFunctionRedefinition];
+      } else {
+        // The name was declared in this scope before; check for conflicting
+        // re-declarations. We have a conflict if either of the declarations
+        // is not a var (in script scope, we also have to ignore legacy const
+        // for compatibility). There is similar code in runtime.cc in the
+        // Declare functions. The function CheckConflictingVarDeclarations
+        // checks for var and let bindings from different scopes whereas this
+        // is a check for conflicting declarations within the same scope. This
+        // check also covers the special case
+        //
+        // function () { let x; { var x; } }
+        //
+        // because the var declaration is hoisted to the function scope where
+        // 'x' is already bound.
+        DCHECK(IsDeclaredVariableMode(var->mode()));
         // In harmony we treat re-declarations as early errors. See
         // ES5 16 for a definition of early errors.
         if (declaration_kind == DeclarationDescriptor::NORMAL) {
@@ -1967,9 +2001,6 @@
         *ok = false;
         return nullptr;
       }
-      Expression* expression = NewThrowSyntaxError(
-          MessageTemplate::kVarRedeclaration, name, declaration->position());
-      declaration_scope->SetIllegalRedeclaration(expression);
     } else if (mode == VAR) {
       var->set_maybe_assigned();
     }
@@ -2093,14 +2124,22 @@
 
 Statement* Parser::ParseFunctionDeclaration(
     ZoneList<const AstRawString*>* names, bool* ok) {
-  // FunctionDeclaration ::
-  //   'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
-  // GeneratorDeclaration ::
-  //   'function' '*' Identifier '(' FormalParameterListopt ')'
-  //      '{' FunctionBody '}'
   Expect(Token::FUNCTION, CHECK_OK);
   int pos = position();
   bool is_generator = Check(Token::MUL);
+  return ParseFunctionDeclaration(pos, is_generator, names, ok);
+}
+
+
+Statement* Parser::ParseFunctionDeclaration(
+    int pos, bool is_generator, ZoneList<const AstRawString*>* names,
+    bool* ok) {
+  // FunctionDeclaration ::
+  //   'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+  // GeneratorDeclaration ::
+  //   'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
+  //
+  // 'function' and '*' (if present) have been consumed by the caller.
   bool is_strict_reserved = false;
   const AstRawString* name = ParseIdentifierOrStrictReservedWord(
       &is_strict_reserved, CHECK_OK);
@@ -2113,8 +2152,7 @@
                          : kFunctionNameValidityUnknown,
       is_generator ? FunctionKind::kGeneratorFunction
                    : FunctionKind::kNormalFunction,
-      pos, FunctionLiteral::kDeclaration, FunctionLiteral::kNormalArity,
-      language_mode(), CHECK_OK);
+      pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
 
   // Even if we're not at the top-level of the global or a function
   // scope, we treat it as such and introduce the function with its
@@ -2151,6 +2189,8 @@
   // ClassDeclaration ::
   //   'class' Identifier ('extends' LeftHandExpression)? '{' ClassBody '}'
   //
+  // 'class' is expected to be consumed by the caller.
+  //
   // A ClassDeclaration
   //
   //   class C { ... }
@@ -2161,7 +2201,6 @@
   //
   // so rewrite it as such.
 
-  Expect(Token::CLASS, CHECK_OK);
   if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
     ReportMessage(MessageTemplate::kSloppyLexical);
     *ok = false;
@@ -2177,30 +2216,10 @@
 
   VariableMode mode = is_strong(language_mode()) ? CONST : LET;
   VariableProxy* proxy = NewUnresolved(name, mode);
-  const bool is_class_declaration = true;
-  Declaration* declaration = factory()->NewVariableDeclaration(
-      proxy, mode, scope_, pos, is_class_declaration,
-      scope_->class_declaration_group_start());
-  Variable* outer_class_variable =
-      Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+  Declaration* declaration =
+      factory()->NewVariableDeclaration(proxy, mode, scope_, pos);
+  Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
   proxy->var()->set_initializer_position(position());
-  // This is needed because a class ("class Name { }") creates two bindings (one
-  // in the outer scope, and one in the class scope). The method is a function
-  // scope inside the inner scope (class scope). The consecutive class
-  // declarations are in the outer scope.
-  if (value->class_variable_proxy() && value->class_variable_proxy()->var() &&
-      outer_class_variable->is_class()) {
-    // In some cases, the outer variable is not detected as a class variable;
-    // this happens e.g., for lazy methods. They are excluded from strong mode
-    // checks for now. TODO(marja, rossberg): re-create variables with the
-    // correct Kind and remove this hack.
-    value->class_variable_proxy()
-        ->var()
-        ->AsClassVariable()
-        ->set_declaration_group_start(
-            outer_class_variable->AsClassVariable()->declaration_group_start());
-  }
-
   Assignment* assignment =
       factory()->NewAssignment(Token::INIT, proxy, value, pos);
   Statement* assignment_statement =
@@ -2281,17 +2300,16 @@
   // is inside an initializer block, it is ignored.
 
   DeclarationParsingResult parsing_result;
-  ParseVariableDeclarations(var_context, &parsing_result, CHECK_OK);
+  Block* result =
+      ParseVariableDeclarations(var_context, &parsing_result, names, CHECK_OK);
   ExpectSemicolon(CHECK_OK);
-
-  Block* result = parsing_result.BuildInitializationBlock(names, CHECK_OK);
   return result;
 }
 
-
-void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
-                                       DeclarationParsingResult* parsing_result,
-                                       bool* ok) {
+Block* Parser::ParseVariableDeclarations(
+    VariableDeclarationContext var_context,
+    DeclarationParsingResult* parsing_result,
+    ZoneList<const AstRawString*>* names, bool* ok) {
   // VariableDeclarations ::
   //   ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
   //
@@ -2311,17 +2329,19 @@
   parsing_result->descriptor.declaration_pos = peek_position();
   parsing_result->descriptor.initialization_pos = peek_position();
   parsing_result->descriptor.mode = VAR;
-  // True if the binding needs initialization. 'let' and 'const' declared
-  // bindings are created uninitialized by their declaration nodes and
-  // need initialization. 'var' declared bindings are always initialized
-  // immediately by their declaration nodes.
-  parsing_result->descriptor.needs_init = false;
+
+  Block* init_block = nullptr;
+  if (var_context != kForStatement) {
+    init_block = factory()->NewBlock(
+        NULL, 1, true, parsing_result->descriptor.declaration_pos);
+  }
+
   if (peek() == Token::VAR) {
     if (is_strong(language_mode())) {
       Scanner::Location location = scanner()->peek_location();
       ReportMessageAt(location, MessageTemplate::kStrongVar);
       *ok = false;
-      return;
+      return nullptr;
     }
     Consume(Token::VAR);
   } else if (peek() == Token::CONST && allow_const()) {
@@ -2334,12 +2354,10 @@
       DCHECK(var_context != kStatement);
       parsing_result->descriptor.mode = CONST;
     }
-    parsing_result->descriptor.needs_init = true;
   } else if (peek() == Token::LET && allow_let()) {
     Consume(Token::LET);
     DCHECK(var_context != kStatement);
     parsing_result->descriptor.mode = LET;
-    parsing_result->descriptor.needs_init = true;
   } else {
     UNREACHABLE();  // by current callers
   }
@@ -2350,7 +2368,6 @@
 
   bool first_declaration = true;
   int bindings_start = peek_position();
-  bool is_for_iteration_variable;
   do {
     FuncNameInferrer::State fni_state(fni_);
 
@@ -2360,27 +2377,20 @@
     Expression* pattern;
     int decl_pos = peek_position();
     {
-      ExpressionClassifier pattern_classifier;
+      ExpressionClassifier pattern_classifier(this);
       Token::Value next = peek();
-      pattern = ParsePrimaryExpression(&pattern_classifier, ok);
-      if (!*ok) return;
-      ValidateBindingPattern(&pattern_classifier, ok);
-      if (!*ok) return;
+      pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
+      ValidateBindingPattern(&pattern_classifier, CHECK_OK);
       if (IsLexicalVariableMode(parsing_result->descriptor.mode)) {
-        ValidateLetPattern(&pattern_classifier, ok);
-        if (!*ok) return;
+        ValidateLetPattern(&pattern_classifier, CHECK_OK);
       }
       if (!allow_harmony_destructuring_bind() && !pattern->IsVariableProxy()) {
         ReportUnexpectedToken(next);
         *ok = false;
-        return;
+        return nullptr;
       }
     }
 
-    bool is_pattern =
-        (pattern->IsObjectLiteral() || pattern->IsArrayLiteral()) &&
-        !pattern->is_parenthesized();
-
     Scanner::Location variable_loc = scanner()->location();
     const AstRawString* single_name =
         pattern->IsVariableProxy() ? pattern->AsVariableProxy()->raw_name()
@@ -2389,25 +2399,13 @@
       if (fni_ != NULL) fni_->PushVariableName(single_name);
     }
 
-    is_for_iteration_variable =
-        var_context == kForStatement &&
-        (peek() == Token::IN || PeekContextualKeyword(CStrVector("of")));
-    if (is_for_iteration_variable &&
-        (parsing_result->descriptor.mode == CONST ||
-         parsing_result->descriptor.mode == CONST_LEGACY)) {
-      parsing_result->descriptor.needs_init = false;
-    }
-
     Expression* value = NULL;
-    // Harmony consts have non-optional initializers.
     int initializer_position = RelocInfo::kNoPosition;
     if (Check(Token::ASSIGN)) {
-      ExpressionClassifier classifier;
+      ExpressionClassifier classifier(this);
       value = ParseAssignmentExpression(var_context != kForStatement,
-                                        &classifier, ok);
-      if (!*ok) return;
-      value = ParserTraits::RewriteNonPattern(value, &classifier, ok);
-      if (!*ok) return;
+                                        &classifier, CHECK_OK);
+      RewriteNonPattern(&classifier, CHECK_OK);
       variable_loc.end_pos = scanner()->location().end_pos;
 
       if (!parsing_result->first_initializer_loc.IsValid()) {
@@ -2424,48 +2422,60 @@
         }
       }
 
-      if (allow_harmony_function_name() && single_name) {
-        if (value->IsFunctionLiteral()) {
-          auto function_literal = value->AsFunctionLiteral();
-          if (function_literal->is_anonymous()) {
-            function_literal->set_raw_name(single_name);
-          }
-        } else if (value->IsClassLiteral()) {
-          auto class_literal = value->AsClassLiteral();
-          if (class_literal->raw_name() == nullptr) {
-            class_literal->set_raw_name(single_name);
-          }
-        }
+      if (allow_harmony_function_name()) {
+        ParserTraits::SetFunctionNameFromIdentifierRef(value, pattern);
       }
 
       // End position of the initializer is after the assignment expression.
       initializer_position = scanner()->location().end_pos;
     } else {
-      if ((parsing_result->descriptor.mode == CONST || is_pattern) &&
-          !is_for_iteration_variable) {
-        ParserTraits::ReportMessageAt(
-            Scanner::Location(decl_pos, scanner()->location().end_pos),
-            MessageTemplate::kDeclarationMissingInitializer,
-            is_pattern ? "destructuring" : "const");
-        *ok = false;
-        return;
+      // Initializers may be either required or implied unless this is a
+      // for-in/of iteration variable.
+      if (var_context != kForStatement || !PeekInOrOf()) {
+        // ES6 'const' and binding patterns require initializers.
+        if (parsing_result->descriptor.mode == CONST ||
+            !pattern->IsVariableProxy()) {
+          ParserTraits::ReportMessageAt(
+              Scanner::Location(decl_pos, scanner()->location().end_pos),
+              MessageTemplate::kDeclarationMissingInitializer,
+              !pattern->IsVariableProxy() ? "destructuring" : "const");
+          *ok = false;
+          return nullptr;
+        }
+
+        // 'let x' and (legacy) 'const x' initialize 'x' to undefined.
+        if (parsing_result->descriptor.mode == LET ||
+            parsing_result->descriptor.mode == CONST_LEGACY) {
+          value = GetLiteralUndefined(position());
+        }
       }
+
       // End position of the initializer is after the variable.
       initializer_position = position();
     }
 
-    // Make sure that 'const x' and 'let x' initialize 'x' to undefined.
-    if (value == NULL && parsing_result->descriptor.needs_init) {
-      value = GetLiteralUndefined(position());
+    DeclarationParsingResult::Declaration decl(pattern, initializer_position,
+                                               value);
+    if (var_context == kForStatement) {
+      // Save the declaration for further handling in ParseForStatement.
+      parsing_result->declarations.Add(decl);
+    } else {
+      // Immediately declare the variable otherwise. This avoids O(N^2)
+      // behavior (where N is the number of variables in a single
+      // declaration) in the PatternRewriter having to do with removing
+      // and adding VariableProxies to the Scope (see bug 4699).
+      DCHECK_NOT_NULL(init_block);
+      PatternRewriter::DeclareAndInitializeVariables(
+          init_block, &parsing_result->descriptor, &decl, names, CHECK_OK);
     }
-
-    parsing_result->declarations.Add(DeclarationParsingResult::Declaration(
-        pattern, initializer_position, value));
     first_declaration = false;
   } while (peek() == Token::COMMA);
 
   parsing_result->bindings_loc =
       Scanner::Location(bindings_start, scanner()->location().end_pos);
+
+  DCHECK(*ok);
+  return init_block;
 }
 
 
@@ -2511,13 +2521,13 @@
           IsClassConstructor(function_state_->kind())) {
         bool is_this = peek() == Token::THIS;
         Expression* expr;
-        ExpressionClassifier classifier;
+        ExpressionClassifier classifier(this);
         if (is_this) {
           expr = ParseStrongInitializationExpression(&classifier, CHECK_OK);
         } else {
           expr = ParseStrongSuperCallExpression(&classifier, CHECK_OK);
         }
-        expr = ParserTraits::RewriteNonPattern(expr, &classifier, CHECK_OK);
+        RewriteNonPattern(&classifier, CHECK_OK);
         switch (peek()) {
           case Token::SEMICOLON:
             Consume(Token::SEMICOLON);
@@ -2728,23 +2738,22 @@
 
     if (IsSubclassConstructor(function_state_->kind())) {
       // For subclass constructors we need to return this in case of undefined
-      // and throw an exception in case of a non object.
+      // return a Smi (transformed into an exception in the ConstructStub)
+      // for a non object.
       //
       //   return expr;
       //
       // Is rewritten as:
       //
       //   return (temp = expr) === undefined ? this :
-      //       %_IsJSReceiver(temp) ? temp : throw new TypeError(...);
+      //       %_IsJSReceiver(temp) ? temp : 1;
+
+      // temp = expr
       Variable* temp = scope_->NewTemporary(
           ast_value_factory()->empty_string());
       Assignment* assign = factory()->NewAssignment(
           Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
 
-      Expression* throw_expression =
-          NewThrowTypeError(MessageTemplate::kDerivedConstructorReturn,
-                            ast_value_factory()->empty_string(), pos);
-
       // %_IsJSReceiver(temp)
       ZoneList<Expression*>* is_spec_object_args =
           new (zone()) ZoneList<Expression*>(1, zone());
@@ -2755,7 +2764,7 @@
       // %_IsJSReceiver(temp) ? temp : throw_expression
       Expression* is_object_conditional = factory()->NewConditional(
           is_spec_object_call, factory()->NewVariableProxy(temp),
-          throw_expression, pos);
+          factory()->NewSmiLiteral(1, pos), pos);
 
       // temp === undefined
       Expression* is_undefined = factory()->NewCompareOperation(
@@ -2768,7 +2777,10 @@
           is_object_conditional, pos);
     }
 
-    return_value->MarkTail();
+    // ES6 14.6.1 Static Semantics: IsInTailPosition
+    if (FLAG_harmony_tailcalls && !is_sloppy(language_mode())) {
+      function_state_->AddExpressionInTailPosition(return_value);
+    }
   }
   ExpectSemicolon(CHECK_OK);
 
@@ -2974,6 +2986,40 @@
       factory()->NewThrow(exception, pos), pos);
 }
 
+class Parser::DontCollectExpressionsInTailPositionScope {
+ public:
+  DontCollectExpressionsInTailPositionScope(
+      Parser::FunctionState* function_state)
+      : function_state_(function_state),
+        old_value_(function_state->collect_expressions_in_tail_position()) {
+    function_state->set_collect_expressions_in_tail_position(false);
+  }
+  ~DontCollectExpressionsInTailPositionScope() {
+    function_state_->set_collect_expressions_in_tail_position(old_value_);
+  }
+
+ private:
+  Parser::FunctionState* function_state_;
+  bool old_value_;
+};
+
+// Collects all return expressions at tail call position in this scope
+// to a separate list.
+class Parser::CollectExpressionsInTailPositionToListScope {
+ public:
+  CollectExpressionsInTailPositionToListScope(
+      Parser::FunctionState* function_state, List<Expression*>* list)
+      : function_state_(function_state), list_(list) {
+    function_state->expressions_in_tail_position().Swap(list_);
+  }
+  ~CollectExpressionsInTailPositionToListScope() {
+    function_state_->expressions_in_tail_position().Swap(list_);
+  }
+
+ private:
+  Parser::FunctionState* function_state_;
+  List<Expression*>* list_;
+};
 
 TryStatement* Parser::ParseTryStatement(bool* ok) {
   // TryStatement ::
@@ -2990,7 +3036,11 @@
   Expect(Token::TRY, CHECK_OK);
   int pos = position();
 
-  Block* try_block = ParseBlock(NULL, CHECK_OK);
+  Block* try_block;
+  {
+    DontCollectExpressionsInTailPositionScope no_tail_calls(function_state_);
+    try_block = ParseBlock(NULL, CHECK_OK);
+  }
 
   Token::Value tok = peek();
   if (tok != Token::CATCH && tok != Token::FINALLY) {
@@ -3002,6 +3052,7 @@
   Scope* catch_scope = NULL;
   Variable* catch_variable = NULL;
   Block* catch_block = NULL;
+  List<Expression*> expressions_in_tail_position_in_catch_block;
   if (tok == Token::CATCH) {
     Consume(Token::CATCH);
 
@@ -3009,7 +3060,7 @@
     catch_scope = NewScope(scope_, CATCH_SCOPE);
     catch_scope->set_start_position(scanner()->location().beg_pos);
 
-    ExpressionClassifier pattern_classifier;
+    ExpressionClassifier pattern_classifier(this);
     Expression* pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
     ValidateBindingPattern(&pattern_classifier, CHECK_OK);
 
@@ -3027,6 +3078,9 @@
     Expect(Token::RPAREN, CHECK_OK);
 
     {
+      CollectExpressionsInTailPositionToListScope
+          collect_expressions_in_tail_position_scope(
+              function_state_, &expressions_in_tail_position_in_catch_block);
       BlockState block_state(&scope_, catch_scope);
 
       // TODO(adamk): Make a version of ParseBlock that takes a scope and
@@ -3047,7 +3101,6 @@
           descriptor.scope = scope_;
           descriptor.hoist_scope = nullptr;
           descriptor.mode = LET;
-          descriptor.needs_init = true;
           descriptor.declaration_pos = pattern->position();
           descriptor.initialization_pos = pattern->position();
 
@@ -3102,6 +3155,11 @@
 
   TryStatement* result = NULL;
   if (catch_block != NULL) {
+    // For a try-catch construct append return expressions from the catch block
+    // to the list of return expressions.
+    function_state_->expressions_in_tail_position().AddAll(
+        expressions_in_tail_position_in_catch_block);
+
     DCHECK(finally_block == NULL);
     DCHECK(catch_scope != NULL && catch_variable != NULL);
     result = factory()->NewTryCatchStatement(try_block, catch_scope,
@@ -3262,6 +3320,7 @@
     }
 
     for_of->Initialize(each, subject, body,
+                       iterator,
                        assign_iterator,
                        next_result,
                        result_done,
@@ -3288,9 +3347,8 @@
   }
 }
 
-
 Statement* Parser::DesugarLexicalBindingsInForStatement(
-    Scope* inner_scope, bool is_const, ZoneList<const AstRawString*>* names,
+    Scope* inner_scope, VariableMode mode, ZoneList<const AstRawString*>* names,
     ForStatement* loop, Statement* init, Expression* cond, Statement* next,
     Statement* body, bool* ok) {
   // ES6 13.7.4.8 specifies that on each loop iteration the let variables are
@@ -3331,7 +3389,6 @@
   //  }
 
   DCHECK(names->length() > 0);
-  Scope* for_scope = scope_;
   ZoneList<Variable*> temps(names->length(), zone());
 
   Block* outer_block = factory()->NewBlock(NULL, names->length() + 4, false,
@@ -3384,150 +3441,155 @@
   ForStatement* outer_loop =
       factory()->NewForStatement(NULL, RelocInfo::kNoPosition);
   outer_block->statements()->Add(outer_loop, zone());
-
-  outer_block->set_scope(for_scope);
-  scope_ = inner_scope;
+  outer_block->set_scope(scope_);
 
   Block* inner_block =
       factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
-  Block* ignore_completion_block = factory()->NewBlock(
-      NULL, names->length() + 3, true, RelocInfo::kNoPosition);
-  ZoneList<Variable*> inner_vars(names->length(), zone());
-  // For each let variable x:
-  //    make statement: let/const x = temp_x.
-  VariableMode mode = is_const ? CONST : LET;
-  for (int i = 0; i < names->length(); i++) {
-    VariableProxy* proxy = NewUnresolved(names->at(i), mode);
-    Declaration* declaration = factory()->NewVariableDeclaration(
-        proxy, mode, scope_, RelocInfo::kNoPosition);
-    Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
-    inner_vars.Add(declaration->proxy()->var(), zone());
-    VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
-    Assignment* assignment = factory()->NewAssignment(
-        Token::INIT, proxy, temp_proxy, RelocInfo::kNoPosition);
-    Statement* assignment_statement =
-        factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
-    DCHECK(init->position() != RelocInfo::kNoPosition);
-    proxy->var()->set_initializer_position(init->position());
-    ignore_completion_block->statements()->Add(assignment_statement, zone());
-  }
-
-  // Make statement: if (first == 1) { first = 0; } else { next; }
-  if (next) {
-    DCHECK(first);
-    Expression* compare = NULL;
-    // Make compare expression: first == 1.
-    {
-      Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
-      VariableProxy* first_proxy = factory()->NewVariableProxy(first);
-      compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
-                                               RelocInfo::kNoPosition);
-    }
-    Statement* clear_first = NULL;
-    // Make statement: first = 0.
-    {
-      VariableProxy* first_proxy = factory()->NewVariableProxy(first);
-      Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
-      Assignment* assignment = factory()->NewAssignment(
-          Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
-      clear_first =
-          factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
-    }
-    Statement* clear_first_or_next = factory()->NewIfStatement(
-        compare, clear_first, next, RelocInfo::kNoPosition);
-    ignore_completion_block->statements()->Add(clear_first_or_next, zone());
-  }
-
-  Variable* flag = scope_->NewTemporary(temp_name);
-  // Make statement: flag = 1.
   {
-    VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
-    Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
-    Assignment* assignment = factory()->NewAssignment(
-        Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
-    Statement* assignment_statement =
-        factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
-    ignore_completion_block->statements()->Add(assignment_statement, zone());
-  }
+    BlockState block_state(&scope_, inner_scope);
 
-  // Make statement: if (!cond) break.
-  if (cond) {
-    Statement* stop =
-        factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
-    Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
-    ignore_completion_block->statements()->Add(
-        factory()->NewIfStatement(cond, noop, stop, cond->position()), zone());
-  }
-
-  inner_block->statements()->Add(ignore_completion_block, zone());
-  // Make cond expression for main loop: flag == 1.
-  Expression* flag_cond = NULL;
-  {
-    Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
-    VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
-    flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
-                                               RelocInfo::kNoPosition);
-  }
-
-  // Create chain of expressions "flag = 0, temp_x = x, ..."
-  Statement* compound_next_statement = NULL;
-  {
-    Expression* compound_next = NULL;
-    // Make expression: flag = 0.
-    {
-      VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
-      Expression* const0 = factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
-      compound_next = factory()->NewAssignment(Token::ASSIGN, flag_proxy,
-                                               const0, RelocInfo::kNoPosition);
-    }
-
-    // Make the comma-separated list of temp_x = x assignments.
-    int inner_var_proxy_pos = scanner()->location().beg_pos;
+    Block* ignore_completion_block = factory()->NewBlock(
+        NULL, names->length() + 3, true, RelocInfo::kNoPosition);
+    ZoneList<Variable*> inner_vars(names->length(), zone());
+    // For each let variable x:
+    //    make statement: let/const x = temp_x.
     for (int i = 0; i < names->length(); i++) {
+      VariableProxy* proxy = NewUnresolved(names->at(i), mode);
+      Declaration* declaration = factory()->NewVariableDeclaration(
+          proxy, mode, scope_, RelocInfo::kNoPosition);
+      Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
+      inner_vars.Add(declaration->proxy()->var(), zone());
       VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
-      VariableProxy* proxy =
-          factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
       Assignment* assignment = factory()->NewAssignment(
-          Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
-      compound_next = factory()->NewBinaryOperation(
-          Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
+          Token::INIT, proxy, temp_proxy, RelocInfo::kNoPosition);
+      Statement* assignment_statement =
+          factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+      DCHECK(init->position() != RelocInfo::kNoPosition);
+      proxy->var()->set_initializer_position(init->position());
+      ignore_completion_block->statements()->Add(assignment_statement, zone());
     }
 
-    compound_next_statement = factory()->NewExpressionStatement(
-        compound_next, RelocInfo::kNoPosition);
-  }
+    // Make statement: if (first == 1) { first = 0; } else { next; }
+    if (next) {
+      DCHECK(first);
+      Expression* compare = NULL;
+      // Make compare expression: first == 1.
+      {
+        Expression* const1 =
+            factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+        VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+        compare = factory()->NewCompareOperation(Token::EQ, first_proxy, const1,
+                                                 RelocInfo::kNoPosition);
+      }
+      Statement* clear_first = NULL;
+      // Make statement: first = 0.
+      {
+        VariableProxy* first_proxy = factory()->NewVariableProxy(first);
+        Expression* const0 =
+            factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+        Assignment* assignment = factory()->NewAssignment(
+            Token::ASSIGN, first_proxy, const0, RelocInfo::kNoPosition);
+        clear_first = factory()->NewExpressionStatement(assignment,
+                                                        RelocInfo::kNoPosition);
+      }
+      Statement* clear_first_or_next = factory()->NewIfStatement(
+          compare, clear_first, next, RelocInfo::kNoPosition);
+      ignore_completion_block->statements()->Add(clear_first_or_next, zone());
+    }
 
-  // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
-  // Note that we re-use the original loop node, which retains its labels
-  // and ensures that any break or continue statements in body point to
-  // the right place.
-  loop->Initialize(NULL, flag_cond, compound_next_statement, body);
-  inner_block->statements()->Add(loop, zone());
+    Variable* flag = scope_->NewTemporary(temp_name);
+    // Make statement: flag = 1.
+    {
+      VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+      Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+      Assignment* assignment = factory()->NewAssignment(
+          Token::ASSIGN, flag_proxy, const1, RelocInfo::kNoPosition);
+      Statement* assignment_statement =
+          factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition);
+      ignore_completion_block->statements()->Add(assignment_statement, zone());
+    }
 
-  // Make statement: {{if (flag == 1) break;}}
-  {
-    Expression* compare = NULL;
-    // Make compare expresion: flag == 1.
+    // Make statement: if (!cond) break.
+    if (cond) {
+      Statement* stop =
+          factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
+      Statement* noop = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+      ignore_completion_block->statements()->Add(
+          factory()->NewIfStatement(cond, noop, stop, cond->position()),
+          zone());
+    }
+
+    inner_block->statements()->Add(ignore_completion_block, zone());
+    // Make cond expression for main loop: flag == 1.
+    Expression* flag_cond = NULL;
     {
       Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
       VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
-      compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
-                                               RelocInfo::kNoPosition);
+      flag_cond = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
+                                                 RelocInfo::kNoPosition);
     }
-    Statement* stop =
-        factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
-    Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
-    Statement* if_flag_break =
-        factory()->NewIfStatement(compare, stop, empty, RelocInfo::kNoPosition);
-    Block* ignore_completion_block =
-        factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
-    ignore_completion_block->statements()->Add(if_flag_break, zone());
-    inner_block->statements()->Add(ignore_completion_block, zone());
-  }
 
-  inner_scope->set_end_position(scanner()->location().end_pos);
-  inner_block->set_scope(inner_scope);
-  scope_ = for_scope;
+    // Create chain of expressions "flag = 0, temp_x = x, ..."
+    Statement* compound_next_statement = NULL;
+    {
+      Expression* compound_next = NULL;
+      // Make expression: flag = 0.
+      {
+        VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+        Expression* const0 =
+            factory()->NewSmiLiteral(0, RelocInfo::kNoPosition);
+        compound_next = factory()->NewAssignment(
+            Token::ASSIGN, flag_proxy, const0, RelocInfo::kNoPosition);
+      }
+
+      // Make the comma-separated list of temp_x = x assignments.
+      int inner_var_proxy_pos = scanner()->location().beg_pos;
+      for (int i = 0; i < names->length(); i++) {
+        VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
+        VariableProxy* proxy =
+            factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
+        Assignment* assignment = factory()->NewAssignment(
+            Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
+        compound_next = factory()->NewBinaryOperation(
+            Token::COMMA, compound_next, assignment, RelocInfo::kNoPosition);
+      }
+
+      compound_next_statement = factory()->NewExpressionStatement(
+          compound_next, RelocInfo::kNoPosition);
+    }
+
+    // Make statement: labels: for (; flag == 1; flag = 0, temp_x = x)
+    // Note that we re-use the original loop node, which retains its labels
+    // and ensures that any break or continue statements in body point to
+    // the right place.
+    loop->Initialize(NULL, flag_cond, compound_next_statement, body);
+    inner_block->statements()->Add(loop, zone());
+
+    // Make statement: {{if (flag == 1) break;}}
+    {
+      Expression* compare = NULL;
+      // Make compare expresion: flag == 1.
+      {
+        Expression* const1 =
+            factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
+        VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
+        compare = factory()->NewCompareOperation(Token::EQ, flag_proxy, const1,
+                                                 RelocInfo::kNoPosition);
+      }
+      Statement* stop =
+          factory()->NewBreakStatement(outer_loop, RelocInfo::kNoPosition);
+      Statement* empty = factory()->NewEmptyStatement(RelocInfo::kNoPosition);
+      Statement* if_flag_break = factory()->NewIfStatement(
+          compare, stop, empty, RelocInfo::kNoPosition);
+      Block* ignore_completion_block =
+          factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+      ignore_completion_block->statements()->Add(if_flag_break, zone());
+      inner_block->statements()->Add(ignore_completion_block, zone());
+    }
+
+    inner_scope->set_end_position(scanner()->location().end_pos);
+    inner_block->set_scope(inner_scope);
+  }
 
   outer_loop->Initialize(NULL, NULL, NULL, inner_block);
   return outer_block;
@@ -3536,18 +3598,14 @@
 
 Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
                                      bool* ok) {
-  // ForStatement ::
-  //   'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
-
   int stmt_pos = peek_position();
-  bool is_const = false;
   Statement* init = NULL;
   ZoneList<const AstRawString*> lexical_bindings(1, zone());
 
   // Create an in-between scope for let-bound iteration variables.
-  Scope* saved_scope = scope_;
   Scope* for_scope = NewScope(scope_, BLOCK_SCOPE);
-  scope_ = for_scope;
+
+  BlockState block_state(&scope_, for_scope);
   Expect(Token::FOR, CHECK_OK);
   Expect(Token::LPAREN, CHECK_OK);
   for_scope->set_start_position(scanner()->location().beg_pos);
@@ -3556,23 +3614,20 @@
   if (peek() != Token::SEMICOLON) {
     if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
         (peek() == Token::LET && IsNextLetKeyword())) {
-      ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
-      is_const = parsing_result.descriptor.mode == CONST;
+      ParseVariableDeclarations(kForStatement, &parsing_result, nullptr,
+                                CHECK_OK);
 
-      int num_decl = parsing_result.declarations.length();
-      bool accept_IN = num_decl >= 1;
       ForEachStatement::VisitMode mode;
       int each_beg_pos = scanner()->location().beg_pos;
       int each_end_pos = scanner()->location().end_pos;
 
-      if (accept_IN && CheckInOrOf(&mode, ok)) {
+      if (CheckInOrOf(&mode, ok)) {
         if (!*ok) return nullptr;
-        if (num_decl != 1) {
-          const char* loop_type =
-              mode == ForEachStatement::ITERATE ? "for-of" : "for-in";
+        if (parsing_result.declarations.length() != 1) {
           ParserTraits::ReportMessageAt(
               parsing_result.bindings_loc,
-              MessageTemplate::kForInOfLoopMultiBindings, loop_type);
+              MessageTemplate::kForInOfLoopMultiBindings,
+              ForEachStatement::VisitModeString(mode));
           *ok = false;
           return nullptr;
         }
@@ -3582,14 +3637,10 @@
             (is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
              IsLexicalVariableMode(parsing_result.descriptor.mode) ||
              !decl.pattern->IsVariableProxy())) {
-          if (mode == ForEachStatement::ITERATE) {
-            ReportMessageAt(parsing_result.first_initializer_loc,
-                            MessageTemplate::kForOfLoopInitializer);
-          } else {
-            // TODO(caitp): This should be an error in sloppy mode too.
-            ReportMessageAt(parsing_result.first_initializer_loc,
-                            MessageTemplate::kForInLoopInitializer);
-          }
+          ParserTraits::ReportMessageAt(
+              parsing_result.first_initializer_loc,
+              MessageTemplate::kForInOfLoopInitializer,
+              ForEachStatement::VisitModeString(mode));
           *ok = false;
           return nullptr;
         }
@@ -3599,6 +3650,7 @@
         // special case for legacy for (var/const x =.... in)
         if (!IsLexicalVariableMode(parsing_result.descriptor.mode) &&
             decl.pattern->IsVariableProxy() && decl.initializer != nullptr) {
+          ++use_counts_[v8::Isolate::kForInInitializer];
           const AstRawString* name =
               decl.pattern->AsVariableProxy()->raw_name();
           VariableProxy* single_var = scope_->NewUnresolved(
@@ -3630,52 +3682,59 @@
         //     let x;  // for TDZ
         //   }
 
-        Variable* temp = scope_->NewTemporary(
-            ast_value_factory()->dot_for_string());
+        Variable* temp =
+            scope_->NewTemporary(ast_value_factory()->dot_for_string());
         ForEachStatement* loop =
             factory()->NewForEachStatement(mode, labels, stmt_pos);
         Target target(&this->target_stack_, loop);
 
-        Expression* enumerable = ParseExpression(true, CHECK_OK);
+        Expression* enumerable;
+        if (mode == ForEachStatement::ITERATE) {
+          ExpressionClassifier classifier(this);
+          enumerable = ParseAssignmentExpression(true, &classifier, CHECK_OK);
+          RewriteNonPattern(&classifier, CHECK_OK);
+        } else {
+          enumerable = ParseExpression(true, CHECK_OK);
+        }
 
         Expect(Token::RPAREN, CHECK_OK);
 
         Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
         body_scope->set_start_position(scanner()->location().beg_pos);
-        scope_ = body_scope;
-
-        Statement* body = ParseSubStatement(NULL, CHECK_OK);
 
         Block* body_block =
             factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition);
 
-        auto each_initialization_block =
-            factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
         {
-          auto descriptor = parsing_result.descriptor;
-          descriptor.declaration_pos = RelocInfo::kNoPosition;
-          descriptor.initialization_pos = RelocInfo::kNoPosition;
-          decl.initializer = factory()->NewVariableProxy(temp);
+          BlockState block_state(&scope_, body_scope);
 
-          PatternRewriter::DeclareAndInitializeVariables(
-              each_initialization_block, &descriptor, &decl,
-              IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings
-                                                     : nullptr,
-              CHECK_OK);
+          Statement* body = ParseSubStatement(NULL, CHECK_OK);
+
+          auto each_initialization_block =
+              factory()->NewBlock(nullptr, 1, true, RelocInfo::kNoPosition);
+          {
+            auto descriptor = parsing_result.descriptor;
+            descriptor.declaration_pos = RelocInfo::kNoPosition;
+            descriptor.initialization_pos = RelocInfo::kNoPosition;
+            decl.initializer = factory()->NewVariableProxy(temp);
+
+            PatternRewriter::DeclareAndInitializeVariables(
+                each_initialization_block, &descriptor, &decl,
+                IsLexicalVariableMode(descriptor.mode) ? &lexical_bindings
+                                                       : nullptr,
+                CHECK_OK);
+          }
+
+          body_block->statements()->Add(each_initialization_block, zone());
+          body_block->statements()->Add(body, zone());
+          VariableProxy* temp_proxy =
+              factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
+          InitializeForEachStatement(loop, temp_proxy, enumerable, body_block,
+                                     false);
         }
-
-        body_block->statements()->Add(each_initialization_block, zone());
-        body_block->statements()->Add(body, zone());
-        VariableProxy* temp_proxy =
-            factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
-        InitializeForEachStatement(loop, temp_proxy, enumerable, body_block,
-                                   false);
-        scope_ = for_scope;
         body_scope->set_end_position(scanner()->location().end_pos);
         body_scope = body_scope->FinalizeBlockScope();
-        if (body_scope != nullptr) {
-          body_block->set_scope(body_scope);
-        }
+        body_block->set_scope(body_scope);
 
         // Create a TDZ for any lexically-bound names.
         if (IsLexicalVariableMode(parsing_result.descriptor.mode)) {
@@ -3688,28 +3747,31 @@
             // TODO(adamk): This needs to be some sort of special
             // INTERNAL variable that's invisible to the debugger
             // but visible to everything else.
-            VariableProxy* tdz_proxy = NewUnresolved(lexical_bindings[i], LET);
+            VariableProxy* tdz_proxy =
+                NewUnresolved(lexical_bindings[i], LET);
             Declaration* tdz_decl = factory()->NewVariableDeclaration(
                 tdz_proxy, LET, scope_, RelocInfo::kNoPosition);
-            Variable* tdz_var = Declare(tdz_decl, DeclarationDescriptor::NORMAL,
-                                        true, CHECK_OK);
+            Variable* tdz_var = Declare(
+                tdz_decl, DeclarationDescriptor::NORMAL, true, CHECK_OK);
             tdz_var->set_initializer_position(position());
           }
         }
 
-        scope_ = saved_scope;
+        Statement* final_loop = loop->IsForOfStatement()
+            ? FinalizeForOfStatement(
+                loop->AsForOfStatement(), RelocInfo::kNoPosition)
+            : loop;
+
         for_scope->set_end_position(scanner()->location().end_pos);
         for_scope = for_scope->FinalizeBlockScope();
         // Parsed for-in loop w/ variable declarations.
         if (init_block != nullptr) {
-          init_block->statements()->Add(loop, zone());
-          if (for_scope != nullptr) {
-            init_block->set_scope(for_scope);
-          }
+          init_block->statements()->Add(final_loop, zone());
+          init_block->set_scope(for_scope);
           return init_block;
         } else {
           DCHECK_NULL(for_scope);
-          return loop;
+          return final_loop;
         }
       } else {
         init = parsing_result.BuildInitializationBlock(
@@ -3720,7 +3782,7 @@
       }
     } else {
       int lhs_beg_pos = peek_position();
-      ExpressionClassifier classifier;
+      ExpressionClassifier classifier(this);
       Expression* expression = ParseExpression(false, &classifier, CHECK_OK);
       int lhs_end_pos = scanner()->location().end_pos;
       ForEachStatement::VisitMode mode;
@@ -3738,8 +3800,7 @@
       if (is_destructuring) {
         ValidateAssignmentPattern(&classifier, CHECK_OK);
       } else {
-        expression =
-            ParserTraits::RewriteNonPattern(expression, &classifier, CHECK_OK);
+        RewriteNonPattern(&classifier, CHECK_OK);
       }
 
       if (is_for_each) {
@@ -3753,7 +3814,15 @@
             factory()->NewForEachStatement(mode, labels, stmt_pos);
         Target target(&this->target_stack_, loop);
 
-        Expression* enumerable = ParseExpression(true, CHECK_OK);
+        Expression* enumerable;
+        if (mode == ForEachStatement::ITERATE) {
+          ExpressionClassifier classifier(this);
+          enumerable = ParseAssignmentExpression(true, &classifier, CHECK_OK);
+          RewriteNonPattern(&classifier, CHECK_OK);
+        } else {
+          enumerable = ParseExpression(true, CHECK_OK);
+        }
+
         Expect(Token::RPAREN, CHECK_OK);
 
         // Make a block around the statement in case a lexical binding
@@ -3763,24 +3832,28 @@
         // expressions in head of the loop should actually have variables
         // resolved in the outer scope.
         Scope* body_scope = NewScope(for_scope, BLOCK_SCOPE);
-        scope_ = body_scope;
-        Block* block =
-            factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
-        Statement* body = ParseSubStatement(NULL, CHECK_OK);
-        block->statements()->Add(body, zone());
-        InitializeForEachStatement(loop, expression, enumerable, block,
-                                   is_destructuring);
-        scope_ = saved_scope;
-        body_scope->set_end_position(scanner()->location().end_pos);
-        body_scope = body_scope->FinalizeBlockScope();
-        if (body_scope != nullptr) {
+        {
+          BlockState block_state(&scope_, body_scope);
+          Block* block =
+              factory()->NewBlock(NULL, 1, false, RelocInfo::kNoPosition);
+          Statement* body = ParseSubStatement(NULL, CHECK_OK);
+          block->statements()->Add(body, zone());
+          InitializeForEachStatement(loop, expression, enumerable, block,
+                                     is_destructuring);
+          body_scope->set_end_position(scanner()->location().end_pos);
+          body_scope = body_scope->FinalizeBlockScope();
           block->set_scope(body_scope);
         }
+
+        Statement* final_loop = loop->IsForOfStatement()
+            ? FinalizeForOfStatement(
+                loop->AsForOfStatement(), RelocInfo::kNoPosition)
+            : loop;
+
         for_scope->set_end_position(scanner()->location().end_pos);
         for_scope = for_scope->FinalizeBlockScope();
         DCHECK(for_scope == nullptr);
-        // Parsed for-in loop.
-        return loop;
+        return final_loop;
 
       } else {
         init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
@@ -3802,40 +3875,42 @@
   }
   Expect(Token::SEMICOLON, CHECK_OK);
 
+  Expression* cond = NULL;
+  Statement* next = NULL;
+  Statement* body = NULL;
+
   // If there are let bindings, then condition and the next statement of the
   // for loop must be parsed in a new scope.
-  Scope* inner_scope = NULL;
+  Scope* inner_scope = scope_;
   if (lexical_bindings.length() > 0) {
     inner_scope = NewScope(for_scope, BLOCK_SCOPE);
     inner_scope->set_start_position(scanner()->location().beg_pos);
-    scope_ = inner_scope;
   }
+  {
+    BlockState block_state(&scope_, inner_scope);
 
-  Expression* cond = NULL;
-  if (peek() != Token::SEMICOLON) {
-    cond = ParseExpression(true, CHECK_OK);
+    if (peek() != Token::SEMICOLON) {
+      cond = ParseExpression(true, CHECK_OK);
+    }
+    Expect(Token::SEMICOLON, CHECK_OK);
+
+    if (peek() != Token::RPAREN) {
+      Expression* exp = ParseExpression(true, CHECK_OK);
+      next = factory()->NewExpressionStatement(exp, exp->position());
+    }
+    Expect(Token::RPAREN, CHECK_OK);
+
+    body = ParseSubStatement(NULL, CHECK_OK);
   }
-  Expect(Token::SEMICOLON, CHECK_OK);
-
-  Statement* next = NULL;
-  if (peek() != Token::RPAREN) {
-    Expression* exp = ParseExpression(true, CHECK_OK);
-    next = factory()->NewExpressionStatement(exp, exp->position());
-  }
-  Expect(Token::RPAREN, CHECK_OK);
-
-  Statement* body = ParseSubStatement(NULL, CHECK_OK);
 
   Statement* result = NULL;
   if (lexical_bindings.length() > 0) {
-    scope_ = for_scope;
+    BlockState block_state(&scope_, for_scope);
     result = DesugarLexicalBindingsInForStatement(
-                 inner_scope, is_const, &lexical_bindings, loop, init, cond,
-                 next, body, CHECK_OK);
-    scope_ = saved_scope;
+        inner_scope, parsing_result.descriptor.mode, &lexical_bindings, loop,
+        init, cond, next, body, CHECK_OK);
     for_scope->set_end_position(scanner()->location().end_pos);
   } else {
-    scope_ = saved_scope;
     for_scope->set_end_position(scanner()->location().end_pos);
     for_scope = for_scope->FinalizeBlockScope();
     if (for_scope) {
@@ -4035,7 +4110,7 @@
   ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ok);
   if (!*ok) return;
 
-  ExpressionClassifier classifier;
+  Type::ExpressionClassifier classifier(parser_);
   if (!parameters->is_simple) {
     classifier.RecordNonSimpleParameter();
   }
@@ -4069,7 +4144,6 @@
     const AstRawString* function_name, Scanner::Location function_name_location,
     FunctionNameValidity function_name_validity, FunctionKind kind,
     int function_token_pos, FunctionLiteral::FunctionType function_type,
-    FunctionLiteral::ArityRestriction arity_restriction,
     LanguageMode language_mode, bool* ok) {
   // Function ::
   //   '(' FormalParameterList? ')' '{' FunctionBody '}'
@@ -4137,17 +4211,18 @@
   int materialized_literal_count = -1;
   int expected_property_count = -1;
   DuplicateFinder duplicate_finder(scanner()->unicode_cache());
-  ExpressionClassifier formals_classifier(&duplicate_finder);
   FunctionLiteral::EagerCompileHint eager_compile_hint =
       parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
                               : FunctionLiteral::kShouldLazyCompile;
   bool should_be_used_once_hint = false;
+  bool has_duplicate_parameters;
   // Parse function.
   {
     AstNodeFactory function_factory(ast_value_factory());
     FunctionState function_state(&function_state_, &scope_, scope, kind,
                                  &function_factory);
     scope_->SetScopeName(function_name);
+    ExpressionClassifier formals_classifier(this, &duplicate_finder);
 
     if (is_generator) {
       // For generators, allocating variables in contexts is currently a win
@@ -4172,11 +4247,15 @@
     Expect(Token::RPAREN, CHECK_OK);
     int formals_end_position = scanner()->location().end_pos;
 
-    CheckArityRestrictions(arity, arity_restriction,
-                           formals.has_rest, start_position,
+    CheckArityRestrictions(arity, kind, formals.has_rest, start_position,
                            formals_end_position, CHECK_OK);
     Expect(Token::LBRACE, CHECK_OK);
 
+    // Don't include the rest parameter into the function's formal parameter
+    // count (esp. the SharedFunctionInfo::internal_formal_parameter_count,
+    // which says whether we need to create an arguments adaptor frame).
+    if (formals.has_rest) arity--;
+
     // Determine if the function can be parsed lazily. Lazy parsing is different
     // from lazy compilation; we need to parse more eagerly than we compile.
 
@@ -4321,10 +4400,10 @@
       // If body can be inspected, rewrite queued destructuring assignments
       ParserTraits::RewriteDestructuringAssignments();
     }
+    has_duplicate_parameters =
+      !formals_classifier.is_valid_formal_parameter_list_without_duplicates();
   }
 
-  bool has_duplicate_parameters =
-      !formals_classifier.is_valid_formal_parameter_list_without_duplicates();
   FunctionLiteral::ParameterFlag duplicate_parameters =
       has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
                                : FunctionLiteral::kNoDuplicateParameters;
@@ -4337,10 +4416,6 @@
   if (should_be_used_once_hint)
     function_literal->set_should_be_used_once_hint();
 
-  if (scope->has_rest_parameter()) {
-    function_literal->set_dont_optimize_reason(kRestParameter);
-  }
-
   if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
   return function_literal;
 }
@@ -4461,15 +4536,18 @@
         scope_(scope) {}
 
  private:
-  void VisitExpression(Expression* expr) {
-    RewritableAssignmentExpression* to_rewrite =
-        expr->AsRewritableAssignmentExpression();
+  void VisitExpression(Expression* expr) override {
+    RewritableExpression* to_rewrite = expr->AsRewritableExpression();
     if (to_rewrite == nullptr || to_rewrite->is_rewritten()) return;
 
     Parser::PatternRewriter::RewriteDestructuringAssignment(parser_, to_rewrite,
                                                             scope_);
   }
 
+  // Code in function literals does not need to be eagerly rewritten, it will be
+  // rewritten when scheduled.
+  void VisitFunctionLiteral(FunctionLiteral* expr) override {}
+
  private:
   Parser* parser_;
   Scope* scope_;
@@ -4497,7 +4575,6 @@
     descriptor.scope = scope_;
     descriptor.hoist_scope = nullptr;
     descriptor.mode = LET;
-    descriptor.needs_init = true;
     descriptor.declaration_pos = parameter.pattern->position();
     // The position that will be used by the AssignmentExpression
     // which copies from the temp parameter to the pattern.
@@ -4597,35 +4674,72 @@
   {
     BlockState block_state(&scope_, inner_scope);
 
-    // For generators, allocate and yield an iterator on function entry.
     if (IsGeneratorFunction(kind)) {
-      ZoneList<Expression*>* arguments =
-          new(zone()) ZoneList<Expression*>(0, zone());
-      CallRuntime* allocation = factory()->NewCallRuntime(
-          Runtime::kCreateJSGeneratorObject, arguments, pos);
-      VariableProxy* init_proxy = factory()->NewVariableProxy(
-          function_state_->generator_object_variable());
-      Assignment* assignment = factory()->NewAssignment(
-          Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
-      VariableProxy* get_proxy = factory()->NewVariableProxy(
-          function_state_->generator_object_variable());
-      Yield* yield = factory()->NewYield(
-          get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
-      body->Add(factory()->NewExpressionStatement(
-          yield, RelocInfo::kNoPosition), zone());
-    }
+      // We produce:
+      //
+      // try { InitialYield; ...body...; FinalYield }
+      // finally { %GeneratorClose(generator) }
+      //
+      // - InitialYield yields the actual generator object.
+      // - FinalYield yields {value: foo, done: true} where foo is the
+      //   completion value of body.  (This is needed here in case the body
+      //   falls through without an explicit return.)
+      // - Any return statement inside the body will be converted into a similar
+      //   FinalYield.
+      // - If the generator terminates for whatever reason, we must close it.
+      //   Hence the finally clause.
 
-    ParseStatementList(body, Token::RBRACE, CHECK_OK);
+      Block* try_block =
+          factory()->NewBlock(nullptr, 3, false, RelocInfo::kNoPosition);
 
-    if (IsGeneratorFunction(kind)) {
+      {
+        ZoneList<Expression*>* arguments =
+            new (zone()) ZoneList<Expression*>(0, zone());
+        CallRuntime* allocation = factory()->NewCallRuntime(
+            Runtime::kCreateJSGeneratorObject, arguments, pos);
+        VariableProxy* init_proxy = factory()->NewVariableProxy(
+            function_state_->generator_object_variable());
+        Assignment* assignment = factory()->NewAssignment(
+            Token::INIT, init_proxy, allocation, RelocInfo::kNoPosition);
+        VariableProxy* get_proxy = factory()->NewVariableProxy(
+            function_state_->generator_object_variable());
+        Yield* yield = factory()->NewYield(
+            get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
+        try_block->statements()->Add(
+            factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
+            zone());
+      }
+
+      ParseStatementList(try_block->statements(), Token::RBRACE, CHECK_OK);
+
       VariableProxy* get_proxy = factory()->NewVariableProxy(
           function_state_->generator_object_variable());
       Expression* undefined =
           factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
       Yield* yield = factory()->NewYield(get_proxy, undefined, Yield::kFinal,
                                          RelocInfo::kNoPosition);
-      body->Add(factory()->NewExpressionStatement(
-          yield, RelocInfo::kNoPosition), zone());
+      try_block->statements()->Add(
+          factory()->NewExpressionStatement(yield, RelocInfo::kNoPosition),
+          zone());
+
+      Block* finally_block =
+          factory()->NewBlock(nullptr, 1, false, RelocInfo::kNoPosition);
+      ZoneList<Expression*>* args =
+          new (zone()) ZoneList<Expression*>(1, zone());
+      VariableProxy* call_proxy = factory()->NewVariableProxy(
+          function_state_->generator_object_variable());
+      args->Add(call_proxy, zone());
+      Expression* call = factory()->NewCallRuntime(
+          Runtime::kGeneratorClose, args, RelocInfo::kNoPosition);
+      finally_block->statements()->Add(
+          factory()->NewExpressionStatement(call, RelocInfo::kNoPosition),
+          zone());
+
+      body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
+                                                  RelocInfo::kNoPosition),
+                zone());
+    } else {
+      ParseStatementList(body, Token::RBRACE, CHECK_OK);
     }
 
     if (IsSubclassConstructor(kind)) {
@@ -4682,6 +4796,13 @@
                     RelocInfo::kNoPosition));
   }
 
+  // ES6 14.6.1 Static Semantics: IsInTailPosition
+  // Mark collected return expressions that are in tail call position.
+  const List<Expression*>& expressions_in_tail_position =
+      function_state_->expressions_in_tail_position();
+  for (int i = 0; i < expressions_in_tail_position.length(); ++i) {
+    expressions_in_tail_position[i]->MarkTail();
+  }
   return result;
 }
 
@@ -4693,6 +4814,8 @@
   if (pre_parse_timer_ != NULL) {
     pre_parse_timer_->Start();
   }
+  TRACE_EVENT0("v8", "V8.PreParse");
+
   DCHECK_EQ(Token::LBRACE, scanner()->current_token());
 
   if (reusable_preparser_ == NULL) {
@@ -4709,6 +4832,7 @@
     SET_ALLOW(strong_mode);
     SET_ALLOW(harmony_do_expressions);
     SET_ALLOW(harmony_function_name);
+    SET_ALLOW(harmony_function_sent);
 #undef SET_ALLOW
   }
   PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
@@ -4751,19 +4875,17 @@
   VariableProxy* proxy = NULL;
   if (name != NULL) {
     proxy = NewUnresolved(name, CONST);
-    const bool is_class_declaration = true;
-    Declaration* declaration = factory()->NewVariableDeclaration(
-        proxy, CONST, block_scope, pos, is_class_declaration,
-        scope_->class_declaration_group_start());
+    Declaration* declaration =
+        factory()->NewVariableDeclaration(proxy, CONST, block_scope, pos);
     Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
   }
 
   Expression* extends = NULL;
   if (Check(Token::EXTENDS)) {
     block_scope->set_start_position(scanner()->location().end_pos);
-    ExpressionClassifier classifier;
+    ExpressionClassifier classifier(this);
     extends = ParseLeftHandSideExpression(&classifier, CHECK_OK);
-    extends = ParserTraits::RewriteNonPattern(extends, &classifier, CHECK_OK);
+    RewriteNonPattern(&classifier, CHECK_OK);
   } else {
     block_scope->set_start_position(scanner()->location().end_pos);
   }
@@ -4784,25 +4906,27 @@
     const bool is_static = false;
     bool is_computed_name = false;  // Classes do not care about computed
                                     // property names here.
-    ExpressionClassifier classifier;
-    const AstRawString* name = nullptr;
+    ExpressionClassifier classifier(this);
+    const AstRawString* property_name = nullptr;
     ObjectLiteral::Property* property = ParsePropertyDefinition(
         &checker, in_class, has_extends, is_static, &is_computed_name,
-        &has_seen_constructor, &classifier, &name, CHECK_OK);
-    property = ParserTraits::RewriteNonPatternObjectLiteralProperty(
-        property, &classifier, CHECK_OK);
+        &has_seen_constructor, &classifier, &property_name, CHECK_OK);
+    RewriteNonPattern(&classifier, CHECK_OK);
 
     if (has_seen_constructor && constructor == NULL) {
       constructor = GetPropertyValue(property)->AsFunctionLiteral();
       DCHECK_NOT_NULL(constructor);
+      constructor->set_raw_name(
+          name != nullptr ? name : ast_value_factory()->empty_string());
     } else {
       properties->Add(property, zone());
     }
 
     if (fni_ != NULL) fni_->Infer();
 
-    if (allow_harmony_function_name()) {
-      SetFunctionNameFromPropertyName(property, name);
+    if (allow_harmony_function_name() &&
+        property_name != ast_value_factory()->constructor_string()) {
+      SetFunctionNameFromPropertyName(property, property_name);
     }
   }
 
@@ -4810,8 +4934,8 @@
   int end_pos = scanner()->location().end_pos;
 
   if (constructor == NULL) {
-    constructor = DefaultConstructor(extends != NULL, block_scope, pos, end_pos,
-                                     block_scope->language_mode());
+    constructor = DefaultConstructor(name, extends != NULL, block_scope, pos,
+                                     end_pos, block_scope->language_mode());
   }
 
   // Note that we do not finalize this block scope because strong
@@ -4823,8 +4947,8 @@
     proxy->var()->set_initializer_position(end_pos);
   }
 
-  return factory()->NewClassLiteral(name, block_scope, proxy, extends,
-                                    constructor, properties, pos, end_pos);
+  return factory()->NewClassLiteral(block_scope, proxy, extends, constructor,
+                                    properties, pos, end_pos);
 }
 
 
@@ -4838,10 +4962,9 @@
   const AstRawString* name = ParseIdentifier(kAllowRestrictedIdentifiers,
                                              CHECK_OK);
   Scanner::Location spread_pos;
-  ExpressionClassifier classifier;
+  ExpressionClassifier classifier(this);
   ZoneList<Expression*>* args =
       ParseArguments(&spread_pos, &classifier, CHECK_OK);
-  args = RewriteNonPatternArguments(args, &classifier, CHECK_OK);
 
   DCHECK(!spread_pos.IsValid());
 
@@ -5051,6 +5174,12 @@
       isolate->CountUsage(v8::Isolate::UseCounterFeature(feature));
     }
   }
+  if (scanner_.FoundHtmlComment()) {
+    isolate->CountUsage(v8::Isolate::kHtmlComment);
+    if (script->line_offset() == 0 && script->column_offset() == 0) {
+      isolate->CountUsage(v8::Isolate::kHtmlCommentInExternalScript);
+    }
+  }
   isolate->counters()->total_preparse_skipped()->Increment(
       total_preparse_skipped_);
 }
@@ -5404,145 +5533,1381 @@
 }
 
 
-Expression* ParserTraits::RewriteNonPattern(
-    Expression* expr, const ExpressionClassifier* classifier, bool* ok) {
-  return parser_->RewriteNonPattern(expr, classifier, ok);
+void ParserTraits::RewriteNonPattern(Type::ExpressionClassifier* classifier,
+                                     bool* ok) {
+  parser_->RewriteNonPattern(classifier, ok);
 }
 
 
-ZoneList<Expression*>* ParserTraits::RewriteNonPatternArguments(
-    ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
-    bool* ok) {
-  return parser_->RewriteNonPatternArguments(args, classifier, ok);
+Zone* ParserTraits::zone() const {
+  return parser_->function_state_->scope()->zone();
 }
 
 
-ObjectLiteralProperty* ParserTraits::RewriteNonPatternObjectLiteralProperty(
-    ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
-    bool* ok) {
-  return parser_->RewriteNonPatternObjectLiteralProperty(property, classifier,
-                                                         ok);
+ZoneList<Expression*>* ParserTraits::GetNonPatternList() const {
+  return parser_->function_state_->non_patterns_to_rewrite();
 }
 
 
-Expression* Parser::RewriteNonPattern(Expression* expr,
-                                      const ExpressionClassifier* classifier,
-                                      bool* ok) {
-  // For the time being, this does no rewriting at all.
-  ValidateExpression(classifier, ok);
-  return expr;
-}
+class NonPatternRewriter : public AstExpressionRewriter {
+ public:
+  NonPatternRewriter(uintptr_t stack_limit, Parser* parser)
+      : AstExpressionRewriter(stack_limit), parser_(parser) {}
+  ~NonPatternRewriter() override {}
 
-
-ZoneList<Expression*>* Parser::RewriteNonPatternArguments(
-    ZoneList<Expression*>* args, const ExpressionClassifier* classifier,
-    bool* ok) {
-  // For the time being, this does no rewriting at all.
-  ValidateExpression(classifier, ok);
-  return args;
-}
-
-
-ObjectLiteralProperty* Parser::RewriteNonPatternObjectLiteralProperty(
-    ObjectLiteralProperty* property, const ExpressionClassifier* classifier,
-    bool* ok) {
-  if (property != nullptr) {
-    Expression* key = RewriteNonPattern(property->key(), classifier, ok);
-    property->set_key(key);
-    Expression* value = RewriteNonPattern(property->value(), classifier, ok);
-    property->set_value(value);
+ private:
+  bool RewriteExpression(Expression* expr) override {
+    if (expr->IsRewritableExpression()) return true;
+    // Rewrite only what could have been a pattern but is not.
+    if (expr->IsArrayLiteral()) {
+      // Spread rewriting in array literals.
+      ArrayLiteral* lit = expr->AsArrayLiteral();
+      VisitExpressions(lit->values());
+      replacement_ = parser_->RewriteSpreads(lit);
+      return false;
+    }
+    if (expr->IsObjectLiteral()) {
+      return true;
+    }
+    if (expr->IsBinaryOperation() &&
+        expr->AsBinaryOperation()->op() == Token::COMMA) {
+      return true;
+    }
+    // Everything else does not need rewriting.
+    return false;
   }
-  return property;
+
+  void VisitObjectLiteralProperty(ObjectLiteralProperty* property) override {
+    if (property == nullptr) return;
+    // Do not rewrite (computed) key expressions
+    AST_REWRITE_PROPERTY(Expression, property, value);
+  }
+
+  Parser* parser_;
+};
+
+
+void Parser::RewriteNonPattern(ExpressionClassifier* classifier, bool* ok) {
+  ValidateExpression(classifier, ok);
+  if (!*ok) return;
+  auto non_patterns_to_rewrite = function_state_->non_patterns_to_rewrite();
+  int begin = classifier->GetNonPatternBegin();
+  int end = non_patterns_to_rewrite->length();
+  if (begin < end) {
+    NonPatternRewriter rewriter(stack_limit_, this);
+    for (int i = begin; i < end; i++) {
+      DCHECK(non_patterns_to_rewrite->at(i)->IsRewritableExpression());
+      rewriter.Rewrite(non_patterns_to_rewrite->at(i));
+    }
+    non_patterns_to_rewrite->Rewind(begin);
+  }
 }
 
 
 void Parser::RewriteDestructuringAssignments() {
-  FunctionState* func = function_state_;
   if (!allow_harmony_destructuring_assignment()) return;
-  const List<DestructuringAssignment>& assignments =
-      func->destructuring_assignments_to_rewrite();
+  const auto& assignments =
+      function_state_->destructuring_assignments_to_rewrite();
   for (int i = assignments.length() - 1; i >= 0; --i) {
     // Rewrite list in reverse, so that nested assignment patterns are rewritten
     // correctly.
-    DestructuringAssignment pair = assignments.at(i);
-    RewritableAssignmentExpression* to_rewrite =
-        pair.assignment->AsRewritableAssignmentExpression();
-    Scope* scope = pair.scope;
+    const DestructuringAssignment& pair = assignments.at(i);
+    RewritableExpression* to_rewrite =
+        pair.assignment->AsRewritableExpression();
     DCHECK_NOT_NULL(to_rewrite);
     if (!to_rewrite->is_rewritten()) {
-      PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite, scope);
+      PatternRewriter::RewriteDestructuringAssignment(this, to_rewrite,
+                                                      pair.scope);
     }
   }
 }
 
 
+Expression* Parser::RewriteSpreads(ArrayLiteral* lit) {
+  // Array literals containing spreads are rewritten using do expressions, e.g.
+  //    [1, 2, 3, ...x, 4, ...y, 5]
+  // is roughly rewritten as:
+  //    do {
+  //      $R = [1, 2, 3];
+  //      for ($i of x) %AppendElement($R, $i);
+  //      %AppendElement($R, 4);
+  //      for ($j of y) %AppendElement($R, $j);
+  //      %AppendElement($R, 5);
+  //      $R
+  //    }
+  // where $R, $i and $j are fresh temporary variables.
+  ZoneList<Expression*>::iterator s = lit->FirstSpread();
+  if (s == lit->EndValue()) return nullptr;  // no spread, no rewriting...
+  Variable* result =
+      scope_->NewTemporary(ast_value_factory()->dot_result_string());
+  // NOTE: The value assigned to R is the whole original array literal,
+  // spreads included. This will be fixed before the rewritten AST is returned.
+  // $R = lit
+  Expression* init_result =
+      factory()->NewAssignment(Token::INIT, factory()->NewVariableProxy(result),
+                               lit, RelocInfo::kNoPosition);
+  Block* do_block =
+      factory()->NewBlock(nullptr, 16, false, RelocInfo::kNoPosition);
+  do_block->statements()->Add(
+      factory()->NewExpressionStatement(init_result, RelocInfo::kNoPosition),
+      zone());
+  // Traverse the array literal starting from the first spread.
+  while (s != lit->EndValue()) {
+    Expression* value = *s++;
+    Spread* spread = value->AsSpread();
+    if (spread == nullptr) {
+      // If the element is not a spread, we're adding a single:
+      // %AppendElement($R, value)
+      ZoneList<Expression*>* append_element_args = NewExpressionList(2, zone());
+      append_element_args->Add(factory()->NewVariableProxy(result), zone());
+      append_element_args->Add(value, zone());
+      do_block->statements()->Add(
+          factory()->NewExpressionStatement(
+              factory()->NewCallRuntime(Runtime::kAppendElement,
+                                        append_element_args,
+                                        RelocInfo::kNoPosition),
+              RelocInfo::kNoPosition),
+          zone());
+    } else {
+      // If it's a spread, we're adding a for/of loop iterating through it.
+      Variable* each =
+          scope_->NewTemporary(ast_value_factory()->dot_for_string());
+      Expression* subject = spread->expression();
+      Variable* iterator =
+          scope_->NewTemporary(ast_value_factory()->dot_iterator_string());
+      Variable* element =
+          scope_->NewTemporary(ast_value_factory()->dot_result_string());
+      // iterator = subject[Symbol.iterator]()
+      Expression* assign_iterator = factory()->NewAssignment(
+          Token::ASSIGN, factory()->NewVariableProxy(iterator),
+          GetIterator(subject, factory(), spread->expression_position()),
+          subject->position());
+      // !%_IsJSReceiver(element = iterator.next()) &&
+      //     %ThrowIteratorResultNotAnObject(element)
+      Expression* next_element;
+      {
+        // element = iterator.next()
+        Expression* iterator_proxy = factory()->NewVariableProxy(iterator);
+        next_element = BuildIteratorNextResult(iterator_proxy, element,
+                                               spread->expression_position());
+      }
+      // element.done
+      Expression* element_done;
+      {
+        Expression* done_literal = factory()->NewStringLiteral(
+            ast_value_factory()->done_string(), RelocInfo::kNoPosition);
+        Expression* element_proxy = factory()->NewVariableProxy(element);
+        element_done = factory()->NewProperty(element_proxy, done_literal,
+                                              RelocInfo::kNoPosition);
+      }
+      // each = element.value
+      Expression* assign_each;
+      {
+        Expression* value_literal = factory()->NewStringLiteral(
+            ast_value_factory()->value_string(), RelocInfo::kNoPosition);
+        Expression* element_proxy = factory()->NewVariableProxy(element);
+        Expression* element_value = factory()->NewProperty(
+            element_proxy, value_literal, RelocInfo::kNoPosition);
+        assign_each = factory()->NewAssignment(
+            Token::ASSIGN, factory()->NewVariableProxy(each), element_value,
+            RelocInfo::kNoPosition);
+      }
+      // %AppendElement($R, each)
+      Statement* append_body;
+      {
+        ZoneList<Expression*>* append_element_args =
+            NewExpressionList(2, zone());
+        append_element_args->Add(factory()->NewVariableProxy(result), zone());
+        append_element_args->Add(factory()->NewVariableProxy(each), zone());
+        append_body = factory()->NewExpressionStatement(
+            factory()->NewCallRuntime(Runtime::kAppendElement,
+                                      append_element_args,
+                                      RelocInfo::kNoPosition),
+            RelocInfo::kNoPosition);
+      }
+      // for (each of spread) %AppendElement($R, each)
+      ForEachStatement* loop = factory()->NewForEachStatement(
+          ForEachStatement::ITERATE, nullptr, RelocInfo::kNoPosition);
+      ForOfStatement* for_of = loop->AsForOfStatement();
+      for_of->Initialize(factory()->NewVariableProxy(each), subject,
+                         append_body, iterator, assign_iterator, next_element,
+                         element_done, assign_each);
+      do_block->statements()->Add(for_of, zone());
+    }
+  }
+  // Now, rewind the original array literal to truncate everything from the
+  // first spread (included) until the end. This fixes $R's initialization.
+  lit->RewindSpreads();
+  return factory()->NewDoExpression(do_block, result, lit->position());
+}
+
+
 void ParserTraits::QueueDestructuringAssignmentForRewriting(Expression* expr) {
-  DCHECK(expr->IsRewritableAssignmentExpression());
+  DCHECK(expr->IsRewritableExpression());
   parser_->function_state_->AddDestructuringAssignment(
       Parser::DestructuringAssignment(expr, parser_->scope_));
 }
 
 
+void ParserTraits::QueueNonPatternForRewriting(Expression* expr) {
+  DCHECK(expr->IsRewritableExpression());
+  parser_->function_state_->AddNonPatternForRewriting(expr);
+}
+
+
 void ParserTraits::SetFunctionNameFromPropertyName(
     ObjectLiteralProperty* property, const AstRawString* name) {
   Expression* value = property->value();
-  if (!value->IsFunctionLiteral() && !value->IsClassLiteral()) return;
 
-  // TODO(adamk): Support computed names.
+  // Computed name setting must happen at runtime.
   if (property->is_computed_name()) return;
+
+  // Getter and setter names are handled here because their names
+  // change in ES2015, even though they are not anonymous.
+  auto function = value->AsFunctionLiteral();
+  if (function != nullptr) {
+    bool is_getter = property->kind() == ObjectLiteralProperty::GETTER;
+    bool is_setter = property->kind() == ObjectLiteralProperty::SETTER;
+    if (is_getter || is_setter) {
+      DCHECK_NOT_NULL(name);
+      const AstRawString* prefix =
+          is_getter ? parser_->ast_value_factory()->get_space_string()
+                    : parser_->ast_value_factory()->set_space_string();
+      function->set_raw_name(
+          parser_->ast_value_factory()->NewConsString(prefix, name));
+      return;
+    }
+  }
+
+  if (!value->IsAnonymousFunctionDefinition()) return;
   DCHECK_NOT_NULL(name);
 
   // Ignore "__proto__" as a name when it's being used to set the [[Prototype]]
   // of an object literal.
   if (property->kind() == ObjectLiteralProperty::PROTOTYPE) return;
 
-  if (value->IsFunctionLiteral()) {
-    auto function = value->AsFunctionLiteral();
-    if (function->is_anonymous()) {
-      if (property->kind() == ObjectLiteralProperty::GETTER) {
-        function->set_raw_name(parser_->ast_value_factory()->NewConsString(
-            parser_->ast_value_factory()->get_space_string(), name));
-      } else if (property->kind() == ObjectLiteralProperty::SETTER) {
-        function->set_raw_name(parser_->ast_value_factory()->NewConsString(
-            parser_->ast_value_factory()->set_space_string(), name));
-      } else {
-        function->set_raw_name(name);
-        DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
-      }
-    }
+  if (function != nullptr) {
+    function->set_raw_name(name);
+    DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
   } else {
     DCHECK(value->IsClassLiteral());
     DCHECK_EQ(ObjectLiteralProperty::COMPUTED, property->kind());
-    auto class_literal = value->AsClassLiteral();
-    if (class_literal->raw_name() == nullptr) {
-      class_literal->set_raw_name(name);
-    }
+    value->AsClassLiteral()->constructor()->set_raw_name(name);
   }
 }
 
 
 void ParserTraits::SetFunctionNameFromIdentifierRef(Expression* value,
                                                     Expression* identifier) {
-  if (!value->IsFunctionLiteral() && !value->IsClassLiteral()) return;
+  if (!value->IsAnonymousFunctionDefinition()) return;
   if (!identifier->IsVariableProxy()) return;
 
   auto name = identifier->AsVariableProxy()->raw_name();
   DCHECK_NOT_NULL(name);
 
-  if (value->IsFunctionLiteral()) {
-    auto function = value->AsFunctionLiteral();
-    if (function->is_anonymous()) {
-      function->set_raw_name(name);
-    }
+  auto function = value->AsFunctionLiteral();
+  if (function != nullptr) {
+    function->set_raw_name(name);
   } else {
     DCHECK(value->IsClassLiteral());
-    auto class_literal = value->AsClassLiteral();
-    if (class_literal->raw_name() == nullptr) {
-      class_literal->set_raw_name(name);
-    }
+    value->AsClassLiteral()->constructor()->set_raw_name(name);
   }
 }
 
 
+// Desugaring of yield*
+// ====================
+//
+// With the help of do-expressions and function.sent, we desugar yield* into a
+// loop containing a "raw" yield (a yield that doesn't wrap an iterator result
+// object around its argument).  Concretely, "yield* iterable" turns into
+// roughly the following code:
+//
+//   do {
+//     const kNext = 0;
+//     const kReturn = 1;
+//     const kThrow = 2;
+//
+//     let input = function.sent;
+//     let mode = kNext;
+//     let output = undefined;
+//
+//     let iterator = iterable[Symbol.iterator]();
+//     if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
+//
+//     while (true) {
+//       // From the generator to the iterator:
+//       // Forward input according to resume mode and obtain output.
+//       switch (mode) {
+//         case kNext:
+//           output = iterator.next(input);
+//           if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+//           break;
+//         case kReturn:
+//           IteratorClose(iterator, input, output);  // See below.
+//           break;
+//         case kThrow:
+//           let iteratorThrow = iterator.throw;
+//           if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
+//             IteratorClose(iterator);  // See below.
+//             throw MakeTypeError(kThrowMethodMissing);
+//           }
+//           output = %_Call(iteratorThrow, iterator, input);
+//           if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+//           break;
+//       }
+//       if (output.done) break;
+//
+//       // From the generator to its user:
+//       // Forward output, receive new input, and determine resume mode.
+//       mode = kReturn;
+//       try {
+//         try {
+//           RawYield(output);  // See explanation above.
+//           mode = kNext;
+//         } catch (error) {
+//           mode = kThrow;
+//         }
+//       } finally {
+//         input = function.sent;
+//         continue;
+//       }
+//     }
+//
+//     output.value;
+//   }
+//
+// IteratorClose(iterator) expands to the following:
+//
+//   let iteratorReturn = iterator.return;
+//   if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return;
+//   let output = %_Call(iteratorReturn, iterator);
+//   if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+//
+// IteratorClose(iterator, input, output) expands to the following:
+//
+//   let iteratorReturn = iterator.return;
+//   if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
+//   output = %_Call(iteratorReturn, iterator, input);
+//   if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+
+
+Expression* ParserTraits::RewriteYieldStar(
+    Expression* generator, Expression* iterable, int pos) {
+
+  const int nopos = RelocInfo::kNoPosition;
+
+  auto factory = parser_->factory();
+  auto avfactory = parser_->ast_value_factory();
+  auto scope = parser_->scope_;
+  auto zone = parser_->zone();
+
+
+  // Forward definition for break/continue statements.
+  WhileStatement* loop = factory->NewWhileStatement(nullptr, nopos);
+
+
+  // let input = undefined;
+  Variable* var_input = scope->NewTemporary(avfactory->empty_string());
+  Statement* initialize_input;
+  {
+    Expression* input_proxy = factory->NewVariableProxy(var_input);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, input_proxy, factory->NewUndefinedLiteral(nopos), nopos);
+    initialize_input = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // let mode = kNext;
+  Variable* var_mode = scope->NewTemporary(avfactory->empty_string());
+  Statement* initialize_mode;
+  {
+    Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+    Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+    Expression* assignment =
+        factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
+    initialize_mode = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // let output = undefined;
+  Variable* var_output = scope->NewTemporary(avfactory->empty_string());
+  Statement* initialize_output;
+  {
+    Expression* output_proxy = factory->NewVariableProxy(var_output);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, output_proxy, factory->NewUndefinedLiteral(nopos),
+        nopos);
+    initialize_output = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // let iterator = iterable[Symbol.iterator];
+  Variable* var_iterator = scope->NewTemporary(avfactory->empty_string());
+  Statement* get_iterator;
+  {
+    Expression* iterator = GetIterator(iterable, factory, nopos);
+    Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, iterator_proxy, iterator, nopos);
+    get_iterator = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // if (!IS_RECEIVER(iterator)) throw MakeTypeError(kSymbolIteratorInvalid);
+  Statement* validate_iterator;
+  {
+    Expression* is_receiver_call;
+    {
+      auto args = new (zone) ZoneList<Expression*>(1, zone);
+      args->Add(factory->NewVariableProxy(var_iterator), zone);
+      is_receiver_call =
+          factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+    }
+
+    Statement* throw_call;
+    {
+      Expression* call = NewThrowTypeError(
+          MessageTemplate::kSymbolIteratorInvalid, avfactory->empty_string(),
+          nopos);
+      throw_call = factory->NewExpressionStatement(call, nopos);
+    }
+
+    validate_iterator = factory->NewIfStatement(
+        is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+  }
+
+
+  // output = iterator.next(input);
+  Statement* call_next;
+  {
+    Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+    Expression* literal =
+        factory->NewStringLiteral(avfactory->next_string(), nopos);
+    Expression* next_property =
+        factory->NewProperty(iterator_proxy, literal, nopos);
+    Expression* input_proxy = factory->NewVariableProxy(var_input);
+    auto args = new (zone) ZoneList<Expression*>(1, zone);
+    args->Add(input_proxy, zone);
+    Expression* call = factory->NewCall(next_property, args, nopos);
+    Expression* output_proxy = factory->NewVariableProxy(var_output);
+    Expression* assignment =
+        factory->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
+    call_next = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+  Statement* validate_next_output;
+  {
+    Expression* is_receiver_call;
+    {
+      auto args = new (zone) ZoneList<Expression*>(1, zone);
+      args->Add(factory->NewVariableProxy(var_output), zone);
+      is_receiver_call =
+          factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+    }
+
+    Statement* throw_call;
+    {
+      auto args = new (zone) ZoneList<Expression*>(1, zone);
+      args->Add(factory->NewVariableProxy(var_output), zone);
+      Expression* call = factory->NewCallRuntime(
+          Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+      throw_call = factory->NewExpressionStatement(call, nopos);
+    }
+
+    validate_next_output = factory->NewIfStatement(
+        is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+  }
+
+
+  // let iteratorThrow = iterator.throw;
+  Variable* var_throw = scope->NewTemporary(avfactory->empty_string());
+  Statement* get_throw;
+  {
+    Expression* iterator_proxy = factory->NewVariableProxy(var_iterator);
+    Expression* literal =
+        factory->NewStringLiteral(avfactory->throw_string(), nopos);
+    Expression* property =
+        factory->NewProperty(iterator_proxy, literal, nopos);
+    Expression* throw_proxy = factory->NewVariableProxy(var_throw);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, throw_proxy, property, nopos);
+    get_throw = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // if (IS_NULL_OR_UNDEFINED(iteratorThrow) {
+  //   IteratorClose(iterator);
+  //   throw MakeTypeError(kThrowMethodMissing);
+  // }
+  Statement* check_throw;
+  {
+    Expression* condition = factory->NewCompareOperation(
+        Token::EQ, factory->NewVariableProxy(var_throw),
+        factory->NewNullLiteral(nopos), nopos);
+
+    Expression* call = NewThrowTypeError(
+        MessageTemplate::kThrowMethodMissing,
+        avfactory->empty_string(), nopos);
+    Statement* throw_call = factory->NewExpressionStatement(call, nopos);
+
+    Block* then = factory->NewBlock(nullptr, 4+1, false, nopos);
+    Variable* var_tmp = scope->NewTemporary(avfactory->empty_string());
+    BuildIteratorClose(
+        then->statements(), var_iterator, factory->NewUndefinedLiteral(nopos),
+        var_tmp);
+    then->statements()->Add(throw_call, zone);
+    check_throw = factory->NewIfStatement(
+        condition, then, factory->NewEmptyStatement(nopos), nopos);
+  }
+
+
+  // output = %_Call(iteratorThrow, iterator, input);
+  Statement* call_throw;
+  {
+    auto args = new (zone) ZoneList<Expression*>(3, zone);
+    args->Add(factory->NewVariableProxy(var_throw), zone);
+    args->Add(factory->NewVariableProxy(var_iterator), zone);
+    args->Add(factory->NewVariableProxy(var_input), zone);
+    Expression* call =
+        factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, factory->NewVariableProxy(var_output), call, nopos);
+    call_throw = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+  Statement* validate_throw_output;
+  {
+    Expression* is_receiver_call;
+    {
+      auto args = new (zone) ZoneList<Expression*>(1, zone);
+      args->Add(factory->NewVariableProxy(var_output), zone);
+      is_receiver_call =
+          factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+    }
+
+    Statement* throw_call;
+    {
+      auto args = new (zone) ZoneList<Expression*>(1, zone);
+      args->Add(factory->NewVariableProxy(var_output), zone);
+      Expression* call = factory->NewCallRuntime(
+          Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+      throw_call = factory->NewExpressionStatement(call, nopos);
+    }
+
+    validate_throw_output = factory->NewIfStatement(
+        is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+  }
+
+
+  // if (output.done) break;
+  Statement* if_done;
+  {
+    Expression* output_proxy = factory->NewVariableProxy(var_output);
+    Expression* literal =
+        factory->NewStringLiteral(avfactory->done_string(), nopos);
+    Expression* property = factory->NewProperty(output_proxy, literal, nopos);
+    BreakStatement* break_loop = factory->NewBreakStatement(loop, nopos);
+    if_done = factory->NewIfStatement(
+        property, break_loop, factory->NewEmptyStatement(nopos), nopos);
+  }
+
+
+  // mode = kReturn;
+  Statement* set_mode_return;
+  {
+    Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+    Expression* kreturn =
+        factory->NewSmiLiteral(JSGeneratorObject::RETURN, nopos);
+    Expression* assignment =
+        factory->NewAssignment(Token::ASSIGN, mode_proxy, kreturn, nopos);
+    set_mode_return = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // RawYield(output);
+  Statement* yield_output;
+  {
+    Expression* output_proxy = factory->NewVariableProxy(var_output);
+    Yield* yield = factory->NewYield(
+        generator, output_proxy, Yield::kInitial, nopos);
+    yield_output = factory->NewExpressionStatement(yield, nopos);
+  }
+
+
+  // mode = kNext;
+  Statement* set_mode_next;
+  {
+    Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+    Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+    Expression* assignment =
+        factory->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
+    set_mode_next = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // mode = kThrow;
+  Statement* set_mode_throw;
+  {
+    Expression* mode_proxy = factory->NewVariableProxy(var_mode);
+    Expression* kthrow =
+        factory->NewSmiLiteral(JSGeneratorObject::THROW, nopos);
+    Expression* assignment =
+        factory->NewAssignment(Token::ASSIGN, mode_proxy, kthrow, nopos);
+    set_mode_throw = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // input = function.sent;
+  Statement* get_input;
+  {
+    Expression* function_sent = FunctionSentExpression(scope, factory, nopos);
+    Expression* input_proxy = factory->NewVariableProxy(var_input);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, input_proxy, function_sent, nopos);
+    get_input = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+
+  // output.value;
+  Statement* get_value;
+  {
+    Expression* output_proxy = factory->NewVariableProxy(var_output);
+    Expression* literal =
+        factory->NewStringLiteral(avfactory->value_string(), nopos);
+    Expression* property = factory->NewProperty(output_proxy, literal, nopos);
+    get_value = factory->NewExpressionStatement(property, nopos);
+  }
+
+
+  // Now put things together.
+
+
+  // try { ... } catch(e) { ... }
+  Statement* try_catch;
+  {
+    Block* try_block = factory->NewBlock(nullptr, 2, false, nopos);
+    try_block->statements()->Add(yield_output, zone);
+    try_block->statements()->Add(set_mode_next, zone);
+
+    Block* catch_block = factory->NewBlock(nullptr, 1, false, nopos);
+    catch_block->statements()->Add(set_mode_throw, zone);
+
+    Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+    const AstRawString* name = avfactory->dot_catch_string();
+    Variable* catch_variable =
+        catch_scope->DeclareLocal(name, VAR, kCreatedInitialized,
+                                               Variable::NORMAL);
+
+    try_catch = factory->NewTryCatchStatement(
+        try_block, catch_scope, catch_variable, catch_block, nopos);
+  }
+
+
+  // try { ... } finally { ... }
+  Statement* try_finally;
+  {
+    Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+    try_block->statements()->Add(try_catch, zone);
+
+    Block* finally = factory->NewBlock(nullptr, 2, false, nopos);
+    finally->statements()->Add(get_input, zone);
+    finally->statements()->Add(
+        factory->NewContinueStatement(loop, nopos), zone);
+
+    try_finally = factory->NewTryFinallyStatement(try_block, finally, nopos);
+  }
+
+
+  // switch (mode) { ... }
+  SwitchStatement* switch_mode = factory->NewSwitchStatement(nullptr, nopos);
+  {
+    auto case_next = new (zone) ZoneList<Statement*>(3, zone);
+    case_next->Add(call_next, zone);
+    case_next->Add(validate_next_output, zone);
+    case_next->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
+
+    auto case_return = new (zone) ZoneList<Statement*>(5, zone);
+    BuildIteratorClose(case_return, var_iterator,
+                       factory->NewVariableProxy(var_input, nopos), var_output);
+    case_return->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
+
+    auto case_throw = new (zone) ZoneList<Statement*>(5, zone);
+    case_throw->Add(get_throw, zone);
+    case_throw->Add(check_throw, zone);
+    case_throw->Add(call_throw, zone);
+    case_throw->Add(validate_throw_output, zone);
+    case_throw->Add(factory->NewBreakStatement(switch_mode, nopos), zone);
+
+    auto cases = new (zone) ZoneList<CaseClause*>(3, zone);
+    Expression* knext = factory->NewSmiLiteral(JSGeneratorObject::NEXT, nopos);
+    Expression* kreturn =
+        factory->NewSmiLiteral(JSGeneratorObject::RETURN, nopos);
+    Expression* kthrow =
+        factory->NewSmiLiteral(JSGeneratorObject::THROW, nopos);
+    cases->Add(factory->NewCaseClause(knext, case_next, nopos), zone);
+    cases->Add(factory->NewCaseClause(kreturn, case_return, nopos), zone);
+    cases->Add(factory->NewCaseClause(kthrow, case_throw, nopos), zone);
+
+    switch_mode->Initialize(factory->NewVariableProxy(var_mode), cases);
+  }
+
+
+  // while (true) { ... }
+  // Already defined earlier: WhileStatement* loop = ...
+  {
+    Block* loop_body = factory->NewBlock(nullptr, 4, false, nopos);
+    loop_body->statements()->Add(switch_mode, zone);
+    loop_body->statements()->Add(if_done, zone);
+    loop_body->statements()->Add(set_mode_return, zone);
+    loop_body->statements()->Add(try_finally, zone);
+
+    loop->Initialize(factory->NewBooleanLiteral(true, nopos), loop_body);
+  }
+
+
+  // do { ... }
+  DoExpression* yield_star;
+  {
+    // The rewriter needs to process the get_value statement only, hence we
+    // put the preceding statements into an init block.
+
+    Block* do_block_ = factory->NewBlock(nullptr, 6, true, nopos);
+    do_block_->statements()->Add(initialize_input, zone);
+    do_block_->statements()->Add(initialize_mode, zone);
+    do_block_->statements()->Add(initialize_output, zone);
+    do_block_->statements()->Add(get_iterator, zone);
+    do_block_->statements()->Add(validate_iterator, zone);
+    do_block_->statements()->Add(loop, zone);
+
+    Block* do_block = factory->NewBlock(nullptr, 2, false, nopos);
+    do_block->statements()->Add(do_block_, zone);
+    do_block->statements()->Add(get_value, zone);
+
+    Variable* dot_result = scope->NewTemporary(avfactory->dot_result_string());
+    yield_star = factory->NewDoExpression(do_block, dot_result, nopos);
+    Rewriter::Rewrite(parser_, yield_star, avfactory);
+  }
+
+  return yield_star;
+}
+
+// Desugaring of (lhs) instanceof (rhs)
+// ====================================
+//
+// We desugar instanceof into a load of property @@hasInstance on the rhs.
+// We end up with roughly the following code (O, C):
+//
+//   do {
+//     let O = lhs;
+//     let C = rhs;
+//     if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck);
+//     let handler_result = C[Symbol.hasInstance];
+//     if (handler_result === undefined) {
+//       if (!IS_CALLABLE(C)) {
+//         throw MakeTypeError(kCalledNonCallableInstanceOf);
+//       }
+//       handler_result = %ordinary_has_instance(C, O);
+//     } else {
+//       handler_result = !!(%_Call(handler_result, C, O));
+//     }
+//     handler_result;
+//   }
+//
+Expression* ParserTraits::RewriteInstanceof(Expression* lhs, Expression* rhs,
+                                            int pos) {
+  const int nopos = RelocInfo::kNoPosition;
+
+  auto factory = parser_->factory();
+  auto avfactory = parser_->ast_value_factory();
+  auto scope = parser_->scope_;
+  auto zone = parser_->zone();
+
+  // let O = lhs;
+  Variable* var_O = scope->NewTemporary(avfactory->empty_string());
+  Statement* get_O;
+  {
+    Expression* O_proxy = factory->NewVariableProxy(var_O);
+    Expression* assignment =
+        factory->NewAssignment(Token::ASSIGN, O_proxy, lhs, nopos);
+    get_O = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+  // let C = lhs;
+  Variable* var_C = scope->NewTemporary(avfactory->empty_string());
+  Statement* get_C;
+  {
+    Expression* C_proxy = factory->NewVariableProxy(var_C);
+    Expression* assignment =
+        factory->NewAssignment(Token::ASSIGN, C_proxy, rhs, nopos);
+    get_C = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+  // if (!IS_RECEIVER(C)) throw MakeTypeError(kNonObjectInInstanceOfCheck);
+  Statement* validate_C;
+  {
+    auto args = new (zone) ZoneList<Expression*>(1, zone);
+    args->Add(factory->NewVariableProxy(var_C), zone);
+    Expression* is_receiver_call =
+        factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+    Expression* call =
+        NewThrowTypeError(MessageTemplate::kNonObjectInInstanceOfCheck,
+                          avfactory->empty_string(), nopos);
+    Statement* throw_call = factory->NewExpressionStatement(call, nopos);
+
+    validate_C =
+        factory->NewIfStatement(is_receiver_call,
+                                factory->NewEmptyStatement(nopos),
+                                throw_call,
+                                nopos);
+  }
+
+  // let handler_result = C[Symbol.hasInstance];
+  Variable* var_handler_result = scope->NewTemporary(avfactory->empty_string());
+  Statement* initialize_handler;
+  {
+    Expression* hasInstance_symbol_literal =
+        factory->NewSymbolLiteral("hasInstance_symbol", RelocInfo::kNoPosition);
+    Expression* prop = factory->NewProperty(factory->NewVariableProxy(var_C),
+                                            hasInstance_symbol_literal, pos);
+    Expression* handler_proxy = factory->NewVariableProxy(var_handler_result);
+    Expression* assignment =
+        factory->NewAssignment(Token::ASSIGN, handler_proxy, prop, nopos);
+    initialize_handler = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+  // if (handler_result === undefined) {
+  //   if (!IS_CALLABLE(C)) {
+  //     throw MakeTypeError(kCalledNonCallableInstanceOf);
+  //   }
+  //   result = %ordinary_has_instance(C, O);
+  // } else {
+  //   handler_result = !!%_Call(handler_result, C, O);
+  // }
+  Statement* call_handler;
+  {
+    Expression* condition = factory->NewCompareOperation(
+        Token::EQ_STRICT, factory->NewVariableProxy(var_handler_result),
+        factory->NewUndefinedLiteral(nopos), nopos);
+
+    Block* then_side = factory->NewBlock(nullptr, 2, false, nopos);
+    {
+      Expression* throw_expr =
+          NewThrowTypeError(MessageTemplate::kCalledNonCallableInstanceOf,
+                            avfactory->empty_string(), nopos);
+      Statement* validate_C = CheckCallable(var_C, throw_expr);
+      ZoneList<Expression*>* args = new (zone) ZoneList<Expression*>(2, zone);
+      args->Add(factory->NewVariableProxy(var_C), zone);
+      args->Add(factory->NewVariableProxy(var_O), zone);
+      CallRuntime* call = factory->NewCallRuntime(
+          Context::ORDINARY_HAS_INSTANCE_INDEX, args, pos);
+      Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
+      Expression* assignment =
+          factory->NewAssignment(Token::ASSIGN, result_proxy, call, nopos);
+      Statement* assignment_return =
+          factory->NewExpressionStatement(assignment, nopos);
+
+      then_side->statements()->Add(validate_C, zone);
+      then_side->statements()->Add(assignment_return, zone);
+    }
+
+    Statement* else_side;
+    {
+      auto args = new (zone) ZoneList<Expression*>(3, zone);
+      args->Add(factory->NewVariableProxy(var_handler_result), zone);
+      args->Add(factory->NewVariableProxy(var_C), zone);
+      args->Add(factory->NewVariableProxy(var_O), zone);
+      Expression* call =
+          factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+      Expression* inner_not =
+          factory->NewUnaryOperation(Token::NOT, call, nopos);
+      Expression* outer_not =
+          factory->NewUnaryOperation(Token::NOT, inner_not, nopos);
+      Expression* result_proxy = factory->NewVariableProxy(var_handler_result);
+      Expression* assignment =
+          factory->NewAssignment(Token::ASSIGN, result_proxy, outer_not, nopos);
+
+      else_side = factory->NewExpressionStatement(assignment, nopos);
+    }
+    call_handler =
+        factory->NewIfStatement(condition, then_side, else_side, nopos);
+  }
+
+  // do { ... }
+  DoExpression* instanceof;
+  {
+    Block* block = factory->NewBlock(nullptr, 5, true, nopos);
+    block->statements()->Add(get_O, zone);
+    block->statements()->Add(get_C, zone);
+    block->statements()->Add(validate_C, zone);
+    block->statements()->Add(initialize_handler, zone);
+    block->statements()->Add(call_handler, zone);
+
+    // Here is the desugared instanceof.
+    instanceof = factory->NewDoExpression(block, var_handler_result, nopos);
+    Rewriter::Rewrite(parser_, instanceof, avfactory);
+  }
+
+  return instanceof;
+}
+
+Statement* ParserTraits::CheckCallable(Variable* var, Expression* error) {
+  auto factory = parser_->factory();
+  auto avfactory = parser_->ast_value_factory();
+  const int nopos = RelocInfo::kNoPosition;
+  Statement* validate_var;
+  {
+    Expression* type_of = factory->NewUnaryOperation(
+        Token::TYPEOF, factory->NewVariableProxy(var), nopos);
+    Expression* function_literal =
+        factory->NewStringLiteral(avfactory->function_string(), nopos);
+    Expression* condition = factory->NewCompareOperation(
+        Token::EQ_STRICT, type_of, function_literal, nopos);
+
+    Statement* throw_call = factory->NewExpressionStatement(error, nopos);
+
+    validate_var = factory->NewIfStatement(
+        condition, factory->NewEmptyStatement(nopos), throw_call, nopos);
+  }
+  return validate_var;
+}
+
+void ParserTraits::BuildIteratorClose(ZoneList<Statement*>* statements,
+                                      Variable* iterator,
+                                      Expression* input,
+                                      Variable* var_output) {
+  //
+  // This function adds four statements to [statements], corresponding to the
+  // following code:
+  //
+  //   let iteratorReturn = iterator.return;
+  //   if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input;
+  //   output = %_Call(iteratorReturn, iterator);
+  //   if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+  //
+
+  const int nopos = RelocInfo::kNoPosition;
+  auto factory = parser_->factory();
+  auto avfactory = parser_->ast_value_factory();
+  auto zone = parser_->zone();
+
+  // let iteratorReturn = iterator.return;
+  Variable* var_return = var_output;  // Reusing the output variable.
+  Statement* get_return;
+  {
+    Expression* iterator_proxy = factory->NewVariableProxy(iterator);
+    Expression* literal =
+        factory->NewStringLiteral(avfactory->return_string(), nopos);
+    Expression* property =
+        factory->NewProperty(iterator_proxy, literal, nopos);
+    Expression* return_proxy = factory->NewVariableProxy(var_return);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, return_proxy, property, nopos);
+    get_return = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+  // if (IS_NULL_OR_UNDEFINED(iteratorReturn) return input;
+  Statement* check_return;
+  {
+    Expression* condition = factory->NewCompareOperation(
+        Token::EQ, factory->NewVariableProxy(var_return),
+        factory->NewNullLiteral(nopos), nopos);
+
+    Statement* return_input = factory->NewReturnStatement(input, nopos);
+
+    check_return = factory->NewIfStatement(
+        condition, return_input, factory->NewEmptyStatement(nopos), nopos);
+  }
+
+  // output = %_Call(iteratorReturn, iterator);
+  Statement* call_return;
+  {
+    auto args = new (zone) ZoneList<Expression*>(3, zone);
+    args->Add(factory->NewVariableProxy(var_return), zone);
+    args->Add(factory->NewVariableProxy(iterator), zone);
+
+    Expression* call =
+        factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+    Expression* output_proxy = factory->NewVariableProxy(var_output);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, output_proxy, call, nopos);
+    call_return = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+  // if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
+  Statement* validate_output;
+  {
+    Expression* is_receiver_call;
+    {
+      auto args = new (zone) ZoneList<Expression*>(1, zone);
+      args->Add(factory->NewVariableProxy(var_output), zone);
+      is_receiver_call =
+          factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+    }
+
+    Statement* throw_call;
+    {
+      auto args = new (zone) ZoneList<Expression*>(1, zone);
+      args->Add(factory->NewVariableProxy(var_output), zone);
+      Expression* call = factory->NewCallRuntime(
+          Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+      throw_call = factory->NewExpressionStatement(call, nopos);
+    }
+
+    validate_output = factory->NewIfStatement(
+        is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+  }
+
+  statements->Add(get_return, zone);
+  statements->Add(check_return, zone);
+  statements->Add(call_return, zone);
+  statements->Add(validate_output, zone);
+}
+
+
+// Runtime encoding of different completion modes.
+enum ForOfLoopBodyCompletion { BODY_COMPLETED, BODY_ABORTED, BODY_THREW };
+
+void ParserTraits::BuildIteratorCloseForCompletion(
+    ZoneList<Statement*>* statements, Variable* iterator,
+    Variable* completion) {
+  //
+  // This function adds two statements to [statements], corresponding to the
+  // following code:
+  //
+  //   let iteratorReturn = iterator.return;
+  //   if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
+  //     let output;
+  //     if (completion === BODY_THREW) {
+  //       if (!IS_CALLABLE(iteratorReturn)) {
+  //         throw MakeTypeError(kReturnMethodNotCallable);
+  //       }
+  //       try { output = %_Call(iteratorReturn, iterator) } catch (_) { }
+  //     } else {
+  //       output = %_Call(iteratorReturn, iterator);
+  //     }
+  //     if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
+  //   }
+  //
+
+  const int nopos = RelocInfo::kNoPosition;
+  auto factory = parser_->factory();
+  auto avfactory = parser_->ast_value_factory();
+  auto scope = parser_->scope_;
+  auto zone = parser_->zone();
+
+  // let output;
+  Variable* var_output = scope->NewTemporary(avfactory->empty_string());
+
+  // let iteratorReturn = iterator.return;
+  Variable* var_return = var_output;  // Reusing the output variable.
+  Statement* get_return;
+  {
+    Expression* iterator_proxy = factory->NewVariableProxy(iterator);
+    Expression* literal =
+        factory->NewStringLiteral(avfactory->return_string(), nopos);
+    Expression* property =
+        factory->NewProperty(iterator_proxy, literal, nopos);
+    Expression* return_proxy = factory->NewVariableProxy(var_return);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, return_proxy, property, nopos);
+    get_return = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+  // if (!IS_CALLABLE(iteratorReturn)) {
+  //   throw MakeTypeError(kReturnMethodNotCallable);
+  // }
+  Statement* check_return_callable;
+  {
+    Expression* throw_expr = NewThrowTypeError(
+        MessageTemplate::kReturnMethodNotCallable,
+        avfactory->empty_string(), nopos);
+    check_return_callable = CheckCallable(var_return, throw_expr);
+  }
+
+  // output = %_Call(iteratorReturn, iterator);
+  Statement* call_return;
+  {
+    auto args = new (zone) ZoneList<Expression*>(2, zone);
+    args->Add(factory->NewVariableProxy(var_return), zone);
+    args->Add(factory->NewVariableProxy(iterator), zone);
+    Expression* call =
+        factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+
+    Expression* output_proxy = factory->NewVariableProxy(var_output);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, output_proxy, call, nopos);
+    call_return = factory->NewExpressionStatement(assignment, nopos);
+  }
+
+  // try { output = %_Call(iteratorReturn, iterator) } catch (_) { }
+  Statement* try_call_return;
+  {
+    auto args = new (zone) ZoneList<Expression*>(2, zone);
+    args->Add(factory->NewVariableProxy(var_return), zone);
+    args->Add(factory->NewVariableProxy(iterator), zone);
+
+    Expression* call =
+        factory->NewCallRuntime(Runtime::kInlineCall, args, nopos);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, factory->NewVariableProxy(var_output), call, nopos);
+
+    Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+    try_block->statements()->Add(
+        factory->NewExpressionStatement(assignment, nopos), zone);
+
+    Block* catch_block = factory->NewBlock(nullptr, 0, false, nopos);
+
+    Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+    Variable* catch_variable = catch_scope->DeclareLocal(
+        avfactory->dot_catch_string(), VAR, kCreatedInitialized,
+        Variable::NORMAL);
+
+    try_call_return = factory->NewTryCatchStatement(
+        try_block, catch_scope, catch_variable, catch_block, nopos);
+  }
+
+  // if (completion === ABRUPT_THROW) {
+  //   #check_return_callable;
+  //   #try_call_return;
+  // } else {
+  //   #call_return;
+  // }
+  Statement* call_return_carefully;
+  {
+    Expression* condition = factory->NewCompareOperation(
+        Token::EQ_STRICT, factory->NewVariableProxy(completion),
+        factory->NewSmiLiteral(BODY_THREW, nopos), nopos);
+
+    Block* then_block = factory->NewBlock(nullptr, 2, false, nopos);
+    then_block->statements()->Add(check_return_callable, zone);
+    then_block->statements()->Add(try_call_return, zone);
+
+    call_return_carefully =
+        factory->NewIfStatement(condition, then_block, call_return, nopos);
+  }
+
+  // if (!IS_RECEIVER(output)) %ThrowIteratorResultNotAnObject(output);
+  Statement* validate_output;
+  {
+    Expression* is_receiver_call;
+    {
+      auto args = new (zone) ZoneList<Expression*>(1, zone);
+      args->Add(factory->NewVariableProxy(var_output), zone);
+      is_receiver_call =
+          factory->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
+    }
+
+    Statement* throw_call;
+    {
+      auto args = new (zone) ZoneList<Expression*>(1, zone);
+      args->Add(factory->NewVariableProxy(var_output), zone);
+      Expression* call = factory->NewCallRuntime(
+          Runtime::kThrowIteratorResultNotAnObject, args, nopos);
+      throw_call = factory->NewExpressionStatement(call, nopos);
+    }
+
+    validate_output = factory->NewIfStatement(
+        is_receiver_call, factory->NewEmptyStatement(nopos), throw_call, nopos);
+  }
+
+  // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) { ... }
+  Statement* maybe_call_return;
+  {
+    Expression* condition = factory->NewCompareOperation(
+        Token::EQ, factory->NewVariableProxy(var_return),
+        factory->NewNullLiteral(nopos), nopos);
+
+    Block* block = factory->NewBlock(nullptr, 2, false, nopos);
+    block->statements()->Add(call_return_carefully, zone);
+    block->statements()->Add(validate_output, zone);
+
+    maybe_call_return = factory->NewIfStatement(
+        condition, factory->NewEmptyStatement(nopos), block, nopos);
+  }
+
+
+  statements->Add(get_return, zone);
+  statements->Add(maybe_call_return, zone);
+}
+
+
+Statement* ParserTraits::FinalizeForOfStatement(ForOfStatement* loop, int pos) {
+  if (!FLAG_harmony_iterator_close) return loop;
+
+  //
+  // This function replaces the loop with the following wrapping:
+  //
+  //   let completion = BODY_COMPLETED;
+  //   try {
+  //     #loop;
+  //   } catch(e) {
+  //     if (completion === BODY_ABORTED) completion = BODY_THREW;
+  //     throw e;
+  //   } finally {
+  //     if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) {
+  //       #BuildIteratorClose(#iterator, completion)  // See above.
+  //     }
+  //   }
+  //
+  // where the loop's body is wrapped as follows:
+  //
+  //   {
+  //     {{completion = BODY_ABORTED;}}
+  //     #loop-body
+  //     {{completion = BODY_COMPLETED;}}
+  //   }
+
+  const int nopos = RelocInfo::kNoPosition;
+  auto factory = parser_->factory();
+  auto avfactory = parser_->ast_value_factory();
+  auto scope = parser_->scope_;
+  auto zone = parser_->zone();
+
+  // let completion = BODY_COMPLETED;
+  Variable* var_completion = scope->NewTemporary(avfactory->empty_string());
+  Statement* initialize_completion;
+  {
+    Expression* proxy = factory->NewVariableProxy(var_completion);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, proxy,
+        factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos);
+    initialize_completion =
+        factory->NewExpressionStatement(assignment, nopos);
+  }
+
+  // if (completion === BODY_ABORTED) completion = BODY_THREW;
+  Statement* set_completion_throw;
+  {
+    Expression* condition = factory->NewCompareOperation(
+        Token::EQ_STRICT, factory->NewVariableProxy(var_completion),
+        factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos);
+
+    Expression* proxy = factory->NewVariableProxy(var_completion);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_THREW, nopos),
+        nopos);
+    Statement* statement = factory->NewExpressionStatement(assignment, nopos);
+    set_completion_throw = factory->NewIfStatement(
+        condition, statement, factory->NewEmptyStatement(nopos), nopos);
+  }
+
+  // if (!(completion === BODY_COMPLETED || IS_UNDEFINED(#iterator))) {
+  //   #BuildIteratorClose(#iterator, completion)
+  // }
+  Block* maybe_close;
+  {
+    Expression* condition1 = factory->NewCompareOperation(
+        Token::EQ_STRICT, factory->NewVariableProxy(var_completion),
+        factory->NewSmiLiteral(BODY_COMPLETED, nopos), nopos);
+    Expression* condition2 = factory->NewCompareOperation(
+        Token::EQ_STRICT, factory->NewVariableProxy(loop->iterator()),
+        factory->NewUndefinedLiteral(nopos), nopos);
+    Expression* condition = factory->NewBinaryOperation(
+        Token::OR, condition1, condition2, nopos);
+
+    Block* block = factory->NewBlock(nullptr, 2, false, nopos);
+    BuildIteratorCloseForCompletion(
+        block->statements(), loop->iterator(), var_completion);
+    DCHECK(block->statements()->length() == 2);
+
+    maybe_close = factory->NewBlock(nullptr, 1, false, nopos);
+    maybe_close->statements()->Add(factory->NewIfStatement(
+        condition, factory->NewEmptyStatement(nopos), block, nopos), zone);
+  }
+
+  // try { #try_block }
+  // catch(e) {
+  //   #set_completion_throw;
+  //   throw e;
+  // }
+  Statement* try_catch;
+  {
+    Scope* catch_scope = NewScope(scope, CATCH_SCOPE);
+    Variable* catch_variable = catch_scope->DeclareLocal(
+        avfactory->dot_catch_string(), VAR, kCreatedInitialized,
+        Variable::NORMAL);
+
+    Statement* rethrow;
+    {
+      Expression* proxy = factory->NewVariableProxy(catch_variable);
+      rethrow = factory->NewExpressionStatement(
+          factory->NewThrow(proxy, nopos), nopos);
+    }
+
+    Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+    try_block->statements()->Add(loop, zone);
+
+    Block* catch_block = factory->NewBlock(nullptr, 2, false, nopos);
+    catch_block->statements()->Add(set_completion_throw, zone);
+    catch_block->statements()->Add(rethrow, zone);
+
+    try_catch = factory->NewTryCatchStatement(
+        try_block, catch_scope, catch_variable, catch_block, nopos);
+  }
+
+  // try { #try_catch } finally { #maybe_close }
+  Statement* try_finally;
+  {
+    Block* try_block = factory->NewBlock(nullptr, 1, false, nopos);
+    try_block->statements()->Add(try_catch, zone);
+
+    try_finally =
+        factory->NewTryFinallyStatement(try_block, maybe_close, nopos);
+  }
+
+  // #initialize_completion;
+  // #try_finally;
+  Statement* final_loop;
+  {
+    Block* block = factory->NewBlock(nullptr, 2, false, nopos);
+    block->statements()->Add(initialize_completion, zone);
+    block->statements()->Add(try_finally, zone);
+    final_loop = block;
+  }
+
+  // {{completion = BODY_ABORTED;}}
+  Statement* set_completion_break;
+  {
+    Expression* proxy = factory->NewVariableProxy(var_completion);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, proxy,
+        factory->NewSmiLiteral(BODY_ABORTED, nopos), nopos);
+
+    Block* block = factory->NewBlock(nullptr, 1, true, nopos);
+    block->statements()->Add(
+        factory->NewExpressionStatement(assignment, nopos), zone);
+    set_completion_break = block;
+  }
+
+  // {{completion = BODY_COMPLETED;}}
+  Statement* set_completion_normal;
+  {
+    Expression* proxy = factory->NewVariableProxy(var_completion);
+    Expression* assignment = factory->NewAssignment(
+        Token::ASSIGN, proxy, factory->NewSmiLiteral(BODY_COMPLETED, nopos),
+        nopos);
+
+    Block* block = factory->NewBlock(nullptr, 1, true, nopos);
+    block->statements()->Add(
+        factory->NewExpressionStatement(assignment, nopos), zone);
+    set_completion_normal = block;
+  }
+
+  // { #set_completion_break; #loop-body; #set_completion_normal }
+  Block* new_body = factory->NewBlock(nullptr, 2, false, nopos);
+  new_body->statements()->Add(set_completion_break, zone);
+  new_body->statements()->Add(loop->body(), zone);
+  new_body->statements()->Add(set_completion_normal, zone);
+
+  loop->set_body(new_body);
+  return final_loop;
+}
+
+
 }  // namespace internal
 }  // namespace v8