Merge V8 5.8.283.32

Test: Build V8 for arm, arm64, x86, x86_64, mips, mips64 and
set a PAC script from the UI on bullhead

Change-Id: I7cc773b5daca34d869e768a1deebae3876f2dfac
diff --git a/src/ast/OWNERS b/src/ast/OWNERS
index b4e1473..16e048a 100644
--- a/src/ast/OWNERS
+++ b/src/ast/OWNERS
@@ -5,5 +5,6 @@
 littledan@chromium.org
 marja@chromium.org
 mstarzinger@chromium.org
+neis@chromium.org
 rossberg@chromium.org
 verwaest@chromium.org
diff --git a/src/ast/ast-expression-rewriter.cc b/src/ast/ast-expression-rewriter.cc
index d0db9ea..f46e21b 100644
--- a/src/ast/ast-expression-rewriter.cc
+++ b/src/ast/ast-expression-rewriter.cc
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/ast/ast.h"
 #include "src/ast/ast-expression-rewriter.h"
+#include "src/ast/ast.h"
+#include "src/objects-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -372,6 +373,9 @@
   NOTHING();
 }
 
+void AstExpressionRewriter::VisitGetIterator(GetIterator* node) {
+  AST_REWRITE_PROPERTY(Expression, node, iterable);
+}
 
 void AstExpressionRewriter::VisitDoExpression(DoExpression* node) {
   REWRITE_THIS(node);
diff --git a/src/ast/ast-function-literal-id-reindexer.cc b/src/ast/ast-function-literal-id-reindexer.cc
new file mode 100644
index 0000000..5cb1e87
--- /dev/null
+++ b/src/ast/ast-function-literal-id-reindexer.cc
@@ -0,0 +1,29 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/ast/ast-function-literal-id-reindexer.h"
+#include "src/objects-inl.h"
+
+#include "src/ast/ast.h"
+
+namespace v8 {
+namespace internal {
+
+AstFunctionLiteralIdReindexer::AstFunctionLiteralIdReindexer(size_t stack_limit,
+                                                             int delta)
+    : AstTraversalVisitor(stack_limit), delta_(delta) {}
+
+AstFunctionLiteralIdReindexer::~AstFunctionLiteralIdReindexer() {}
+
+void AstFunctionLiteralIdReindexer::Reindex(Expression* pattern) {
+  Visit(pattern);
+}
+
+void AstFunctionLiteralIdReindexer::VisitFunctionLiteral(FunctionLiteral* lit) {
+  AstTraversalVisitor::VisitFunctionLiteral(lit);
+  lit->set_function_literal_id(lit->function_literal_id() + delta_);
+}
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/ast/ast-function-literal-id-reindexer.h b/src/ast/ast-function-literal-id-reindexer.h
new file mode 100644
index 0000000..837595f
--- /dev/null
+++ b/src/ast/ast-function-literal-id-reindexer.h
@@ -0,0 +1,36 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_AST_AST_FUNCTION_LITERAL_ID_REINDEXER
+#define V8_AST_AST_FUNCTION_LITERAL_ID_REINDEXER
+
+#include "src/ast/ast-traversal-visitor.h"
+#include "src/base/macros.h"
+
+namespace v8 {
+namespace internal {
+
+// Changes the ID of all FunctionLiterals in the given Expression by adding the
+// given delta.
+class AstFunctionLiteralIdReindexer final
+    : public AstTraversalVisitor<AstFunctionLiteralIdReindexer> {
+ public:
+  AstFunctionLiteralIdReindexer(size_t stack_limit, int delta);
+  ~AstFunctionLiteralIdReindexer();
+
+  void Reindex(Expression* pattern);
+
+  // AstTraversalVisitor implementation.
+  void VisitFunctionLiteral(FunctionLiteral* lit);
+
+ private:
+  int delta_;
+
+  DISALLOW_COPY_AND_ASSIGN(AstFunctionLiteralIdReindexer);
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_AST_AST_FUNCTION_LITERAL_ID_REINDEXER
diff --git a/src/ast/ast-literal-reindexer.cc b/src/ast/ast-literal-reindexer.cc
deleted file mode 100644
index 81a5225..0000000
--- a/src/ast/ast-literal-reindexer.cc
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2015 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "src/ast/ast-literal-reindexer.h"
-
-#include "src/ast/ast.h"
-#include "src/ast/scopes.h"
-
-namespace v8 {
-namespace internal {
-
-
-void AstLiteralReindexer::VisitVariableDeclaration(VariableDeclaration* node) {
-  VisitVariableProxy(node->proxy());
-}
-
-
-void AstLiteralReindexer::VisitEmptyStatement(EmptyStatement* node) {}
-
-
-void AstLiteralReindexer::VisitSloppyBlockFunctionStatement(
-    SloppyBlockFunctionStatement* node) {
-  Visit(node->statement());
-}
-
-
-void AstLiteralReindexer::VisitContinueStatement(ContinueStatement* node) {}
-
-
-void AstLiteralReindexer::VisitBreakStatement(BreakStatement* node) {}
-
-
-void AstLiteralReindexer::VisitDebuggerStatement(DebuggerStatement* node) {}
-
-
-void AstLiteralReindexer::VisitNativeFunctionLiteral(
-    NativeFunctionLiteral* node) {}
-
-
-void AstLiteralReindexer::VisitDoExpression(DoExpression* node) {
-  Visit(node->block());
-  Visit(node->result());
-}
-
-
-void AstLiteralReindexer::VisitLiteral(Literal* node) {}
-
-
-void AstLiteralReindexer::VisitRegExpLiteral(RegExpLiteral* node) {
-  UpdateIndex(node);
-}
-
-
-void AstLiteralReindexer::VisitVariableProxy(VariableProxy* node) {}
-
-
-void AstLiteralReindexer::VisitThisFunction(ThisFunction* node) {}
-
-
-void AstLiteralReindexer::VisitSuperPropertyReference(
-    SuperPropertyReference* node) {
-  Visit(node->this_var());
-  Visit(node->home_object());
-}
-
-
-void AstLiteralReindexer::VisitSuperCallReference(SuperCallReference* node) {
-  Visit(node->this_var());
-  Visit(node->new_target_var());
-  Visit(node->this_function_var());
-}
-
-
-void AstLiteralReindexer::VisitRewritableExpression(
-    RewritableExpression* node) {
-  Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitExpressionStatement(ExpressionStatement* node) {
-  Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitReturnStatement(ReturnStatement* node) {
-  Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitYield(Yield* node) {
-  Visit(node->generator_object());
-  Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitThrow(Throw* node) { Visit(node->exception()); }
-
-
-void AstLiteralReindexer::VisitUnaryOperation(UnaryOperation* node) {
-  Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitCountOperation(CountOperation* node) {
-  Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitBlock(Block* node) {
-  VisitStatements(node->statements());
-}
-
-
-void AstLiteralReindexer::VisitFunctionDeclaration(FunctionDeclaration* node) {
-  VisitVariableProxy(node->proxy());
-  VisitFunctionLiteral(node->fun());
-}
-
-
-void AstLiteralReindexer::VisitCallRuntime(CallRuntime* node) {
-  VisitArguments(node->arguments());
-}
-
-
-void AstLiteralReindexer::VisitWithStatement(WithStatement* node) {
-  Visit(node->expression());
-  Visit(node->statement());
-}
-
-
-void AstLiteralReindexer::VisitDoWhileStatement(DoWhileStatement* node) {
-  Visit(node->body());
-  Visit(node->cond());
-}
-
-
-void AstLiteralReindexer::VisitWhileStatement(WhileStatement* node) {
-  Visit(node->cond());
-  Visit(node->body());
-}
-
-
-void AstLiteralReindexer::VisitTryCatchStatement(TryCatchStatement* node) {
-  Visit(node->try_block());
-  Visit(node->catch_block());
-}
-
-
-void AstLiteralReindexer::VisitTryFinallyStatement(TryFinallyStatement* node) {
-  Visit(node->try_block());
-  Visit(node->finally_block());
-}
-
-
-void AstLiteralReindexer::VisitProperty(Property* node) {
-  Visit(node->key());
-  Visit(node->obj());
-}
-
-
-void AstLiteralReindexer::VisitAssignment(Assignment* node) {
-  Visit(node->target());
-  Visit(node->value());
-}
-
-
-void AstLiteralReindexer::VisitBinaryOperation(BinaryOperation* node) {
-  Visit(node->left());
-  Visit(node->right());
-}
-
-
-void AstLiteralReindexer::VisitCompareOperation(CompareOperation* node) {
-  Visit(node->left());
-  Visit(node->right());
-}
-
-
-void AstLiteralReindexer::VisitSpread(Spread* node) {
-  // This is reachable because ParserBase::ParseArrowFunctionLiteral calls
-  // ReindexLiterals before calling RewriteDestructuringAssignments.
-  Visit(node->expression());
-}
-
-
-void AstLiteralReindexer::VisitEmptyParentheses(EmptyParentheses* node) {}
-
-
-void AstLiteralReindexer::VisitForInStatement(ForInStatement* node) {
-  Visit(node->each());
-  Visit(node->enumerable());
-  Visit(node->body());
-}
-
-
-void AstLiteralReindexer::VisitForOfStatement(ForOfStatement* node) {
-  Visit(node->assign_iterator());
-  Visit(node->next_result());
-  Visit(node->result_done());
-  Visit(node->assign_each());
-  Visit(node->body());
-}
-
-
-void AstLiteralReindexer::VisitConditional(Conditional* node) {
-  Visit(node->condition());
-  Visit(node->then_expression());
-  Visit(node->else_expression());
-}
-
-
-void AstLiteralReindexer::VisitIfStatement(IfStatement* node) {
-  Visit(node->condition());
-  Visit(node->then_statement());
-  if (node->HasElseStatement()) {
-    Visit(node->else_statement());
-  }
-}
-
-
-void AstLiteralReindexer::VisitSwitchStatement(SwitchStatement* node) {
-  Visit(node->tag());
-  ZoneList<CaseClause*>* cases = node->cases();
-  for (int i = 0; i < cases->length(); i++) {
-    VisitCaseClause(cases->at(i));
-  }
-}
-
-
-void AstLiteralReindexer::VisitCaseClause(CaseClause* node) {
-  if (!node->is_default()) Visit(node->label());
-  VisitStatements(node->statements());
-}
-
-
-void AstLiteralReindexer::VisitForStatement(ForStatement* node) {
-  if (node->init() != NULL) Visit(node->init());
-  if (node->cond() != NULL) Visit(node->cond());
-  if (node->next() != NULL) Visit(node->next());
-  Visit(node->body());
-}
-
-
-void AstLiteralReindexer::VisitClassLiteral(ClassLiteral* node) {
-  if (node->extends()) Visit(node->extends());
-  if (node->constructor()) Visit(node->constructor());
-  if (node->class_variable_proxy()) {
-    VisitVariableProxy(node->class_variable_proxy());
-  }
-  for (int i = 0; i < node->properties()->length(); i++) {
-    VisitLiteralProperty(node->properties()->at(i));
-  }
-}
-
-void AstLiteralReindexer::VisitObjectLiteral(ObjectLiteral* node) {
-  UpdateIndex(node);
-  for (int i = 0; i < node->properties()->length(); i++) {
-    VisitLiteralProperty(node->properties()->at(i));
-  }
-}
-
-void AstLiteralReindexer::VisitLiteralProperty(LiteralProperty* node) {
-  Visit(node->key());
-  Visit(node->value());
-}
-
-
-void AstLiteralReindexer::VisitArrayLiteral(ArrayLiteral* node) {
-  UpdateIndex(node);
-  for (int i = 0; i < node->values()->length(); i++) {
-    Visit(node->values()->at(i));
-  }
-}
-
-
-void AstLiteralReindexer::VisitCall(Call* node) {
-  Visit(node->expression());
-  VisitArguments(node->arguments());
-}
-
-
-void AstLiteralReindexer::VisitCallNew(CallNew* node) {
-  Visit(node->expression());
-  VisitArguments(node->arguments());
-}
-
-
-void AstLiteralReindexer::VisitStatements(ZoneList<Statement*>* statements) {
-  if (statements == NULL) return;
-  for (int i = 0; i < statements->length(); i++) {
-    Visit(statements->at(i));
-  }
-}
-
-
-void AstLiteralReindexer::VisitDeclarations(
-    ZoneList<Declaration*>* declarations) {
-  for (int i = 0; i < declarations->length(); i++) {
-    Visit(declarations->at(i));
-  }
-}
-
-
-void AstLiteralReindexer::VisitArguments(ZoneList<Expression*>* arguments) {
-  for (int i = 0; i < arguments->length(); i++) {
-    Visit(arguments->at(i));
-  }
-}
-
-
-void AstLiteralReindexer::VisitFunctionLiteral(FunctionLiteral* node) {
-  // We don't recurse into the declarations or body of the function literal:
-}
-
-void AstLiteralReindexer::Reindex(Expression* pattern) { Visit(pattern); }
-}  // namespace internal
-}  // namespace v8
diff --git a/src/ast/ast-literal-reindexer.h b/src/ast/ast-literal-reindexer.h
deleted file mode 100644
index 4e0ca6b..0000000
--- a/src/ast/ast-literal-reindexer.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef V8_AST_AST_LITERAL_REINDEXER
-#define V8_AST_AST_LITERAL_REINDEXER
-
-#include "src/ast/ast.h"
-#include "src/ast/scopes.h"
-
-namespace v8 {
-namespace internal {
-
-class AstLiteralReindexer final : public AstVisitor<AstLiteralReindexer> {
- public:
-  AstLiteralReindexer() : next_index_(0) {}
-
-  int count() const { return next_index_; }
-  void Reindex(Expression* pattern);
-
- private:
-#define DEFINE_VISIT(type) void Visit##type(type* node);
-  AST_NODE_LIST(DEFINE_VISIT)
-#undef DEFINE_VISIT
-
-  void VisitStatements(ZoneList<Statement*>* statements);
-  void VisitDeclarations(ZoneList<Declaration*>* declarations);
-  void VisitArguments(ZoneList<Expression*>* arguments);
-  void VisitLiteralProperty(LiteralProperty* property);
-
-  void UpdateIndex(MaterializedLiteral* literal) {
-    literal->literal_index_ = next_index_++;
-  }
-
-  int next_index_;
-
-  DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
-  DISALLOW_COPY_AND_ASSIGN(AstLiteralReindexer);
-};
-}  // namespace internal
-}  // namespace v8
-
-#endif  // V8_AST_AST_LITERAL_REINDEXER
diff --git a/src/ast/ast-numbering.cc b/src/ast/ast-numbering.cc
index 82f9767..499760d 100644
--- a/src/ast/ast-numbering.cc
+++ b/src/ast/ast-numbering.cc
@@ -6,22 +6,27 @@
 
 #include "src/ast/ast.h"
 #include "src/ast/scopes.h"
+#include "src/compiler.h"
+#include "src/objects-inl.h"
 
 namespace v8 {
 namespace internal {
 
 class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> {
  public:
-  AstNumberingVisitor(Isolate* isolate, Zone* zone)
-      : isolate_(isolate),
-        zone_(zone),
+  AstNumberingVisitor(uintptr_t stack_limit, Zone* zone,
+                      Compiler::EagerInnerFunctionLiterals* eager_literals)
+      : zone_(zone),
+        eager_literals_(eager_literals),
         next_id_(BailoutId::FirstUsable().ToInt()),
         yield_count_(0),
         properties_(zone),
+        language_mode_(SLOPPY),
         slot_cache_(zone),
+        disable_crankshaft_reason_(kNoReason),
         dont_optimize_reason_(kNoReason),
         catch_prediction_(HandlerTable::UNCAUGHT) {
-    InitializeAstVisitor(isolate);
+    InitializeAstVisitor(stack_limit);
   }
 
   bool Renumber(FunctionLiteral* node);
@@ -32,10 +37,12 @@
   AST_NODE_LIST(DEFINE_VISIT)
 #undef DEFINE_VISIT
 
+  void VisitVariableProxy(VariableProxy* node, TypeofMode typeof_mode);
   void VisitVariableProxyReference(VariableProxy* node);
   void VisitPropertyReference(Property* node);
   void VisitReference(Expression* expr);
 
+  void VisitStatementsAndDeclarations(Block* node);
   void VisitStatements(ZoneList<Statement*>* statements);
   void VisitDeclarations(Declaration::List* declarations);
   void VisitArguments(ZoneList<Expression*>* arguments);
@@ -55,25 +62,43 @@
     dont_optimize_reason_ = reason;
     DisableSelfOptimization();
   }
-  void DisableCrankshaft(BailoutReason reason) {
-    properties_.flags() |= AstProperties::kDontCrankshaft;
+  void DisableFullCodegenAndCrankshaft(BailoutReason reason) {
+    disable_crankshaft_reason_ = reason;
+    properties_.flags() |= AstProperties::kMustUseIgnitionTurbo;
   }
 
   template <typename Node>
   void ReserveFeedbackSlots(Node* node) {
-    node->AssignFeedbackVectorSlots(isolate_, properties_.get_spec(),
-                                    &slot_cache_);
+    node->AssignFeedbackSlots(properties_.get_spec(), language_mode_,
+                              &slot_cache_);
   }
 
+  class LanguageModeScope {
+   public:
+    LanguageModeScope(AstNumberingVisitor* visitor, LanguageMode language_mode)
+        : visitor_(visitor), outer_language_mode_(visitor->language_mode_) {
+      visitor_->language_mode_ = language_mode;
+    }
+    ~LanguageModeScope() { visitor_->language_mode_ = outer_language_mode_; }
+
+   private:
+    AstNumberingVisitor* visitor_;
+    LanguageMode outer_language_mode_;
+  };
+
   BailoutReason dont_optimize_reason() const { return dont_optimize_reason_; }
 
-  Isolate* isolate_;
+  Zone* zone() const { return zone_; }
+
   Zone* zone_;
+  Compiler::EagerInnerFunctionLiterals* eager_literals_;
   int next_id_;
   int yield_count_;
   AstProperties properties_;
-  // The slot cache allows us to reuse certain feedback vector slots.
-  FeedbackVectorSlotCache slot_cache_;
+  LanguageMode language_mode_;
+  // The slot cache allows us to reuse certain feedback slots.
+  FeedbackSlotCache slot_cache_;
+  BailoutReason disable_crankshaft_reason_;
   BailoutReason dont_optimize_reason_;
   HandlerTable::CatchPrediction catch_prediction_;
 
@@ -112,8 +137,7 @@
 
 void AstNumberingVisitor::VisitDebuggerStatement(DebuggerStatement* node) {
   IncrementNodeCount();
-  DisableOptimization(kDebuggerStatement);
-  node->set_base_id(ReserveIdRange(DebuggerStatement::num_ids()));
+  DisableFullCodegenAndCrankshaft(kDebuggerStatement);
 }
 
 
@@ -122,6 +146,7 @@
   IncrementNodeCount();
   DisableOptimization(kNativeFunctionLiteral);
   node->set_base_id(ReserveIdRange(NativeFunctionLiteral::num_ids()));
+  ReserveFeedbackSlots(node);
 }
 
 
@@ -142,6 +167,7 @@
 void AstNumberingVisitor::VisitRegExpLiteral(RegExpLiteral* node) {
   IncrementNodeCount();
   node->set_base_id(ReserveIdRange(RegExpLiteral::num_ids()));
+  ReserveFeedbackSlots(node);
 }
 
 
@@ -149,10 +175,11 @@
   IncrementNodeCount();
   switch (node->var()->location()) {
     case VariableLocation::LOOKUP:
-      DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup);
+      DisableFullCodegenAndCrankshaft(
+          kReferenceToAVariableWhichRequiresDynamicLookup);
       break;
     case VariableLocation::MODULE:
-      DisableCrankshaft(kReferenceToModuleVariable);
+      DisableFullCodegenAndCrankshaft(kReferenceToModuleVariable);
       break;
     default:
       break;
@@ -160,10 +187,14 @@
   node->set_base_id(ReserveIdRange(VariableProxy::num_ids()));
 }
 
+void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node,
+                                             TypeofMode typeof_mode) {
+  VisitVariableProxyReference(node);
+  node->AssignFeedbackSlots(properties_.get_spec(), typeof_mode, &slot_cache_);
+}
 
 void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) {
-  VisitVariableProxyReference(node);
-  ReserveFeedbackSlots(node);
+  VisitVariableProxy(node, NOT_INSIDE_TYPEOF);
 }
 
 
@@ -176,7 +207,7 @@
 void AstNumberingVisitor::VisitSuperPropertyReference(
     SuperPropertyReference* node) {
   IncrementNodeCount();
-  DisableCrankshaft(kSuperReference);
+  DisableFullCodegenAndCrankshaft(kSuperReference);
   node->set_base_id(ReserveIdRange(SuperPropertyReference::num_ids()));
   Visit(node->this_var());
   Visit(node->home_object());
@@ -185,7 +216,7 @@
 
 void AstNumberingVisitor::VisitSuperCallReference(SuperCallReference* node) {
   IncrementNodeCount();
-  DisableCrankshaft(kSuperReference);
+  DisableFullCodegenAndCrankshaft(kSuperReference);
   node->set_base_id(ReserveIdRange(SuperCallReference::num_ids()));
   Visit(node->this_var());
   Visit(node->new_target_var());
@@ -202,6 +233,9 @@
 void AstNumberingVisitor::VisitReturnStatement(ReturnStatement* node) {
   IncrementNodeCount();
   Visit(node->expression());
+
+  DCHECK(!node->is_async_return() ||
+         properties_.flags() & AstProperties::kMustUseIgnitionTurbo);
 }
 
 
@@ -225,7 +259,12 @@
 void AstNumberingVisitor::VisitUnaryOperation(UnaryOperation* node) {
   IncrementNodeCount();
   node->set_base_id(ReserveIdRange(UnaryOperation::num_ids()));
-  Visit(node->expression());
+  if ((node->op() == Token::TYPEOF) && node->expression()->IsVariableProxy()) {
+    VariableProxy* proxy = node->expression()->AsVariableProxy();
+    VisitVariableProxy(proxy, INSIDE_TYPEOF);
+  } else {
+    Visit(node->expression());
+  }
 }
 
 
@@ -240,10 +279,21 @@
 void AstNumberingVisitor::VisitBlock(Block* node) {
   IncrementNodeCount();
   node->set_base_id(ReserveIdRange(Block::num_ids()));
-  if (node->scope() != NULL) VisitDeclarations(node->scope()->declarations());
-  VisitStatements(node->statements());
+  Scope* scope = node->scope();
+  if (scope != nullptr) {
+    LanguageModeScope language_mode_scope(this, scope->language_mode());
+    VisitStatementsAndDeclarations(node);
+  } else {
+    VisitStatementsAndDeclarations(node);
+  }
 }
 
+void AstNumberingVisitor::VisitStatementsAndDeclarations(Block* node) {
+  Scope* scope = node->scope();
+  DCHECK(scope == nullptr || !scope->HasBeenRemoved());
+  if (scope) VisitDeclarations(scope->declarations());
+  VisitStatements(node->statements());
+}
 
 void AstNumberingVisitor::VisitFunctionDeclaration(FunctionDeclaration* node) {
   IncrementNodeCount();
@@ -282,8 +332,7 @@
 
 void AstNumberingVisitor::VisitWithStatement(WithStatement* node) {
   IncrementNodeCount();
-  DisableCrankshaft(kWithStatement);
-  node->set_base_id(ReserveIdRange(WithStatement::num_ids()));
+  DisableFullCodegenAndCrankshaft(kWithStatement);
   Visit(node->expression());
   Visit(node->statement());
 }
@@ -312,8 +361,9 @@
 
 
 void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) {
+  DCHECK(node->scope() == nullptr || !node->scope()->HasBeenRemoved());
   IncrementNodeCount();
-  DisableCrankshaft(kTryCatchStatement);
+  DisableFullCodegenAndCrankshaft(kTryCatchStatement);
   {
     const HandlerTable::CatchPrediction old_prediction = catch_prediction_;
     // This node uses its own prediction, unless it's "uncaught", in which case
@@ -332,7 +382,7 @@
 
 void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) {
   IncrementNodeCount();
-  DisableCrankshaft(kTryFinallyStatement);
+  DisableFullCodegenAndCrankshaft(kTryFinallyStatement);
   // We can't know whether the finally block will override ("catch") an
   // exception thrown in the try block, so we just adopt the outer prediction.
   node->set_catch_prediction(catch_prediction_);
@@ -393,14 +443,25 @@
   ReserveFeedbackSlots(node);
 }
 
-
-void AstNumberingVisitor::VisitSpread(Spread* node) { UNREACHABLE(); }
-
+void AstNumberingVisitor::VisitSpread(Spread* node) {
+  IncrementNodeCount();
+  // We can only get here from spread calls currently.
+  DisableFullCodegenAndCrankshaft(kSpreadCall);
+  node->set_base_id(ReserveIdRange(Spread::num_ids()));
+  Visit(node->expression());
+}
 
 void AstNumberingVisitor::VisitEmptyParentheses(EmptyParentheses* node) {
   UNREACHABLE();
 }
 
+void AstNumberingVisitor::VisitGetIterator(GetIterator* node) {
+  IncrementNodeCount();
+  DisableFullCodegenAndCrankshaft(kGetIterator);
+  node->set_base_id(ReserveIdRange(GetIterator::num_ids()));
+  Visit(node->iterable());
+  ReserveFeedbackSlots(node);
+}
 
 void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
   IncrementNodeCount();
@@ -417,7 +478,7 @@
 
 void AstNumberingVisitor::VisitForOfStatement(ForOfStatement* node) {
   IncrementNodeCount();
-  DisableCrankshaft(kForOfStatement);
+  DisableFullCodegenAndCrankshaft(kForOfStatement);
   node->set_base_id(ReserveIdRange(ForOfStatement::num_ids()));
   Visit(node->assign_iterator());  // Not part of loop.
   node->set_first_yield_id(yield_count_);
@@ -484,8 +545,8 @@
 
 void AstNumberingVisitor::VisitClassLiteral(ClassLiteral* node) {
   IncrementNodeCount();
-  DisableCrankshaft(kClassLiteral);
-  node->set_base_id(ReserveIdRange(node->num_ids()));
+  DisableFullCodegenAndCrankshaft(kClassLiteral);
+  node->set_base_id(ReserveIdRange(ClassLiteral::num_ids()));
   if (node->extends()) Visit(node->extends());
   if (node->constructor()) Visit(node->constructor());
   if (node->class_variable_proxy()) {
@@ -504,7 +565,7 @@
   for (int i = 0; i < node->properties()->length(); i++) {
     VisitLiteralProperty(node->properties()->at(i));
   }
-  node->BuildConstantProperties(isolate_);
+  node->InitDepthAndFlags();
   // Mark all computed expressions that are bound to a key that
   // is shadowed by a later occurrence of the same key. For the
   // marked expressions, no store code will be is emitted.
@@ -513,7 +574,8 @@
 }
 
 void AstNumberingVisitor::VisitLiteralProperty(LiteralProperty* node) {
-  if (node->is_computed_name()) DisableCrankshaft(kComputedPropertyName);
+  if (node->is_computed_name())
+    DisableFullCodegenAndCrankshaft(kComputedPropertyName);
   Visit(node->key());
   Visit(node->value());
 }
@@ -524,12 +586,15 @@
   for (int i = 0; i < node->values()->length(); i++) {
     Visit(node->values()->at(i));
   }
-  node->BuildConstantElements(isolate_);
+  node->InitDepthAndFlags();
   ReserveFeedbackSlots(node);
 }
 
 
 void AstNumberingVisitor::VisitCall(Call* node) {
+  if (node->is_possibly_eval()) {
+    DisableFullCodegenAndCrankshaft(kFunctionCallsEval);
+  }
   IncrementNodeCount();
   ReserveFeedbackSlots(node);
   node->set_base_id(ReserveIdRange(Call::num_ids()));
@@ -569,8 +634,20 @@
 void AstNumberingVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
   IncrementNodeCount();
   node->set_base_id(ReserveIdRange(FunctionLiteral::num_ids()));
-  // We don't recurse into the declarations or body of the function literal:
-  // you have to separately Renumber() each FunctionLiteral that you compile.
+  if (node->ShouldEagerCompile()) {
+    if (eager_literals_) {
+      eager_literals_->Add(new (zone())
+                               ThreadedListZoneEntry<FunctionLiteral*>(node));
+    }
+
+    // If the function literal is being eagerly compiled, recurse into the
+    // declarations and body of the function literal.
+    if (!AstNumbering::Renumber(stack_limit_, zone_, node, eager_literals_)) {
+      SetStackOverflow();
+      return;
+    }
+  }
+  ReserveFeedbackSlots(node);
 }
 
 
@@ -584,37 +661,65 @@
 
 bool AstNumberingVisitor::Renumber(FunctionLiteral* node) {
   DeclarationScope* scope = node->scope();
-  if (scope->new_target_var()) DisableCrankshaft(kSuperReference);
-  if (scope->calls_eval()) DisableCrankshaft(kFunctionCallsEval);
-  if (scope->arguments() != NULL && !scope->arguments()->IsStackAllocated()) {
-    DisableCrankshaft(kContextAllocatedArguments);
+  DCHECK(!scope->HasBeenRemoved());
+
+  if (scope->new_target_var() != nullptr ||
+      scope->this_function_var() != nullptr) {
+    DisableFullCodegenAndCrankshaft(kSuperReference);
+  }
+
+  if (scope->arguments() != nullptr &&
+      !scope->arguments()->IsStackAllocated()) {
+    DisableFullCodegenAndCrankshaft(kContextAllocatedArguments);
   }
 
   if (scope->rest_parameter() != nullptr) {
-    DisableCrankshaft(kRestParameter);
+    DisableFullCodegenAndCrankshaft(kRestParameter);
   }
 
-  if (IsGeneratorFunction(node->kind()) || IsAsyncFunction(node->kind())) {
-    DisableCrankshaft(kGenerator);
+  if (IsResumableFunction(node->kind())) {
+    DisableFullCodegenAndCrankshaft(kGenerator);
   }
 
   if (IsClassConstructor(node->kind())) {
-    DisableCrankshaft(kClassConstructorFunction);
+    DisableFullCodegenAndCrankshaft(kClassConstructorFunction);
   }
 
+  LanguageModeScope language_mode_scope(this, node->language_mode());
+
   VisitDeclarations(scope->declarations());
   VisitStatements(node->body());
 
   node->set_ast_properties(&properties_);
   node->set_dont_optimize_reason(dont_optimize_reason());
   node->set_yield_count(yield_count_);
+
+  if (FLAG_trace_opt) {
+    if (disable_crankshaft_reason_ != kNoReason) {
+      // TODO(leszeks): This is a quick'n'dirty fix to allow the debug name of
+      // the function to be accessed in the below print. This DCHECK will fail
+      // if we move ast numbering off the main thread, but that won't be before
+      // we remove FCG, in which case this entire check isn't necessary anyway.
+      AllowHandleDereference allow_deref;
+      DCHECK(!node->debug_name().is_null());
+
+      PrintF("[enforcing Ignition and TurboFan for %s because: %s\n",
+             node->debug_name()->ToCString().get(),
+             GetBailoutReason(disable_crankshaft_reason_));
+    }
+  }
+
   return !HasStackOverflow();
 }
 
+bool AstNumbering::Renumber(
+    uintptr_t stack_limit, Zone* zone, FunctionLiteral* function,
+    Compiler::EagerInnerFunctionLiterals* eager_literals) {
+  DisallowHeapAllocation no_allocation;
+  DisallowHandleAllocation no_handles;
+  DisallowHandleDereference no_deref;
 
-bool AstNumbering::Renumber(Isolate* isolate, Zone* zone,
-                            FunctionLiteral* function) {
-  AstNumberingVisitor visitor(isolate, zone);
+  AstNumberingVisitor visitor(stack_limit, zone, eager_literals);
   return visitor.Renumber(function);
 }
 }  // namespace internal
diff --git a/src/ast/ast-numbering.h b/src/ast/ast-numbering.h
index 7327895..bea441d 100644
--- a/src/ast/ast-numbering.h
+++ b/src/ast/ast-numbering.h
@@ -5,6 +5,8 @@
 #ifndef V8_AST_AST_NUMBERING_H_
 #define V8_AST_AST_NUMBERING_H_
 
+#include <stdint.h>
+
 namespace v8 {
 namespace internal {
 
@@ -12,11 +14,20 @@
 class FunctionLiteral;
 class Isolate;
 class Zone;
+template <typename T>
+class ThreadedList;
+template <typename T>
+class ThreadedListZoneEntry;
+template <typename T>
+class ZoneVector;
 
 namespace AstNumbering {
 // Assign type feedback IDs, bailout IDs, and generator yield IDs to an AST node
-// tree; perform catch prediction for TryStatements.
-bool Renumber(Isolate* isolate, Zone* zone, FunctionLiteral* function);
+// tree; perform catch prediction for TryStatements. If |eager_literals| is
+// non-null, adds any eager inner literal functions into it.
+bool Renumber(
+    uintptr_t stack_limit, Zone* zone, FunctionLiteral* function,
+    ThreadedList<ThreadedListZoneEntry<FunctionLiteral*>>* eager_literals);
 }
 
 // Some details on yield IDs
diff --git a/src/ast/ast-traversal-visitor.h b/src/ast/ast-traversal-visitor.h
index d93e02f..6d0c386 100644
--- a/src/ast/ast-traversal-visitor.h
+++ b/src/ast/ast-traversal-visitor.h
@@ -288,7 +288,7 @@
   DeclarationScope* scope = expr->scope();
   RECURSE_EXPRESSION(VisitDeclarations(scope->declarations()));
   // A lazily parsed function literal won't have a body.
-  if (expr->scope()->is_lazily_parsed()) return;
+  if (expr->scope()->was_lazily_parsed()) return;
   RECURSE_EXPRESSION(VisitStatements(expr->body()));
 }
 
@@ -471,6 +471,12 @@
 }
 
 template <class Subclass>
+void AstTraversalVisitor<Subclass>::VisitGetIterator(GetIterator* expr) {
+  PROCESS_EXPRESSION(expr);
+  RECURSE_EXPRESSION(Visit(expr->iterable()));
+}
+
+template <class Subclass>
 void AstTraversalVisitor<Subclass>::VisitSuperPropertyReference(
     SuperPropertyReference* expr) {
   PROCESS_EXPRESSION(expr);
diff --git a/src/ast/ast-types.cc b/src/ast/ast-types.cc
index 49551dd..3dde864 100644
--- a/src/ast/ast-types.cc
+++ b/src/ast/ast-types.cc
@@ -7,6 +7,7 @@
 #include "src/ast/ast-types.h"
 
 #include "src/handles-inl.h"
+#include "src/objects-inl.h"
 #include "src/ostreams.h"
 
 namespace v8 {
@@ -156,6 +157,8 @@
     case ONE_BYTE_STRING_TYPE:
     case CONS_STRING_TYPE:
     case CONS_ONE_BYTE_STRING_TYPE:
+    case THIN_STRING_TYPE:
+    case THIN_ONE_BYTE_STRING_TYPE:
     case SLICED_STRING_TYPE:
     case SLICED_ONE_BYTE_STRING_TYPE:
     case EXTERNAL_STRING_TYPE:
@@ -192,8 +195,6 @@
     }
     case HEAP_NUMBER_TYPE:
       return kNumber & kTaggedPointer;
-    case SIMD128_VALUE_TYPE:
-      return kSimd;
     case JS_OBJECT_TYPE:
     case JS_ARGUMENTS_TYPE:
     case JS_ERROR_TYPE:
@@ -209,7 +210,6 @@
     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
     case JS_GENERATOR_OBJECT_TYPE:
     case JS_MODULE_NAMESPACE_TYPE:
-    case JS_FIXED_ARRAY_ITERATOR_TYPE:
     case JS_ARRAY_BUFFER_TYPE:
     case JS_ARRAY_TYPE:
     case JS_REGEXP_TYPE:  // TODO(rossberg): there should be a RegExp type.
@@ -220,6 +220,7 @@
     case JS_SET_ITERATOR_TYPE:
     case JS_MAP_ITERATOR_TYPE:
     case JS_STRING_ITERATOR_TYPE:
+    case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
 
     case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
     case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
@@ -259,6 +260,7 @@
 
     case JS_WEAK_MAP_TYPE:
     case JS_WEAK_SET_TYPE:
+    case JS_PROMISE_CAPABILITY_TYPE:
     case JS_PROMISE_TYPE:
     case JS_BOUND_FUNCTION_TYPE:
       DCHECK(!map->is_undetectable());
@@ -304,19 +306,18 @@
     case PROMISE_REACTION_JOB_INFO_TYPE:
     case FUNCTION_TEMPLATE_INFO_TYPE:
     case OBJECT_TEMPLATE_INFO_TYPE:
-    case SIGNATURE_INFO_TYPE:
-    case TYPE_SWITCH_INFO_TYPE:
     case ALLOCATION_MEMENTO_TYPE:
     case TYPE_FEEDBACK_INFO_TYPE:
     case ALIASED_ARGUMENTS_ENTRY_TYPE:
-    case BOX_TYPE:
     case DEBUG_INFO_TYPE:
     case BREAK_POINT_INFO_TYPE:
     case CELL_TYPE:
     case WEAK_CELL_TYPE:
     case PROTOTYPE_INFO_TYPE:
+    case TUPLE2_TYPE:
     case TUPLE3_TYPE:
     case CONTEXT_EXTENSION_TYPE:
+    case CONSTANT_ELEMENTS_PAIR_TYPE:
       UNREACHABLE();
       return kNone;
   }
@@ -1295,13 +1296,6 @@
   return i::SmiValuesAre31Bits() ? kUnsigned30 : kUnsigned31;
 }
 
-#define CONSTRUCT_SIMD_TYPE(NAME, Name, name, lane_count, lane_type) \
-  AstType* AstType::Name(Isolate* isolate, Zone* zone) {             \
-    return Class(i::handle(isolate->heap()->name##_map()), zone);    \
-  }
-SIMD128_TYPES(CONSTRUCT_SIMD_TYPE)
-#undef CONSTRUCT_SIMD_TYPE
-
 // -----------------------------------------------------------------------------
 // Instantiations.
 
diff --git a/src/ast/ast-types.h b/src/ast/ast-types.h
index 0b6e23f..ea0be65 100644
--- a/src/ast/ast-types.h
+++ b/src/ast/ast-types.h
@@ -156,15 +156,15 @@
 #define AST_REPRESENTATION(k) ((k) & AstBitsetType::kRepresentation)
 #define AST_SEMANTIC(k)       ((k) & AstBitsetType::kSemantic)
 
+// Bits 21-22 are available.
 #define AST_REPRESENTATION_BITSET_TYPE_LIST(V)    \
   V(None,               0)                    \
-  V(UntaggedBit,        1u << 22 | kSemantic) \
-  V(UntaggedIntegral8,  1u << 23 | kSemantic) \
-  V(UntaggedIntegral16, 1u << 24 | kSemantic) \
-  V(UntaggedIntegral32, 1u << 25 | kSemantic) \
-  V(UntaggedFloat32,    1u << 26 | kSemantic) \
-  V(UntaggedFloat64,    1u << 27 | kSemantic) \
-  V(UntaggedSimd128,    1u << 28 | kSemantic) \
+  V(UntaggedBit,        1u << 23 | kSemantic) \
+  V(UntaggedIntegral8,  1u << 24 | kSemantic) \
+  V(UntaggedIntegral16, 1u << 25 | kSemantic) \
+  V(UntaggedIntegral32, 1u << 26 | kSemantic) \
+  V(UntaggedFloat32,    1u << 27 | kSemantic) \
+  V(UntaggedFloat64,    1u << 28 | kSemantic) \
   V(UntaggedPointer,    1u << 29 | kSemantic) \
   V(TaggedSigned,       1u << 30 | kSemantic) \
   V(TaggedPointer,      1u << 31 | kSemantic) \
@@ -197,13 +197,12 @@
   V(Symbol,              1u << 12 | AST_REPRESENTATION(kTaggedPointer)) \
   V(InternalizedString,  1u << 13 | AST_REPRESENTATION(kTaggedPointer)) \
   V(OtherString,         1u << 14 | AST_REPRESENTATION(kTaggedPointer)) \
-  V(Simd,                1u << 15 | AST_REPRESENTATION(kTaggedPointer)) \
-  V(OtherObject,         1u << 17 | AST_REPRESENTATION(kTaggedPointer)) \
+  V(OtherObject,         1u << 15 | AST_REPRESENTATION(kTaggedPointer)) \
   V(OtherUndetectable,   1u << 16 | AST_REPRESENTATION(kTaggedPointer)) \
-  V(Proxy,               1u << 18 | AST_REPRESENTATION(kTaggedPointer)) \
-  V(Function,            1u << 19 | AST_REPRESENTATION(kTaggedPointer)) \
-  V(Hole,                1u << 20 | AST_REPRESENTATION(kTaggedPointer)) \
-  V(OtherInternal,       1u << 21 |                                     \
+  V(Proxy,               1u << 17 | AST_REPRESENTATION(kTaggedPointer)) \
+  V(Function,            1u << 18 | AST_REPRESENTATION(kTaggedPointer)) \
+  V(Hole,                1u << 19 | AST_REPRESENTATION(kTaggedPointer)) \
+  V(OtherInternal,       1u << 20 |                                     \
                          AST_REPRESENTATION(kTagged | kUntagged))       \
   \
   V(Signed31,                   kUnsigned30 | kNegative31) \
@@ -232,11 +231,10 @@
   V(NullOrUndefined,            kNull | kUndefined) \
   V(Undetectable,               kNullOrUndefined | kOtherUndetectable) \
   V(NumberOrOddball,            kNumber | kNullOrUndefined | kBoolean | kHole) \
-  V(NumberOrSimdOrString,       kNumber | kSimd | kString) \
   V(NumberOrString,             kNumber | kString) \
   V(NumberOrUndefined,          kNumber | kUndefined) \
   V(PlainPrimitive,             kNumberOrString | kBoolean | kNullOrUndefined) \
-  V(Primitive,                  kSymbol | kSimd | kPlainPrimitive) \
+  V(Primitive,                  kSymbol | kPlainPrimitive) \
   V(DetectableReceiver,         kFunction | kOtherObject | kProxy) \
   V(Object,                     kFunction | kOtherObject | kOtherUndetectable) \
   V(Receiver,                   kObject | kProxy) \
@@ -770,11 +768,6 @@
     return tuple;
   }
 
-#define CONSTRUCT_SIMD_TYPE(NAME, Name, name, lane_count, lane_type) \
-  static AstType* Name(Isolate* isolate, Zone* zone);
-  SIMD128_TYPES(CONSTRUCT_SIMD_TYPE)
-#undef CONSTRUCT_SIMD_TYPE
-
   static AstType* Union(AstType* type1, AstType* type2, Zone* zone);
   static AstType* Intersect(AstType* type1, AstType* type2, Zone* zone);
 
diff --git a/src/ast/ast-value-factory.cc b/src/ast/ast-value-factory.cc
index ed2976f..b160c48 100644
--- a/src/ast/ast-value-factory.cc
+++ b/src/ast/ast-value-factory.cc
@@ -28,6 +28,8 @@
 #include "src/ast/ast-value-factory.h"
 
 #include "src/api.h"
+#include "src/char-predicates-inl.h"
+#include "src/objects-inl.h"
 #include "src/objects.h"
 #include "src/utils.h"
 
@@ -127,6 +129,36 @@
   return false;
 }
 
+bool AstRawString::Compare(void* a, void* b) {
+  const AstRawString* lhs = static_cast<AstRawString*>(a);
+  const AstRawString* rhs = static_cast<AstRawString*>(b);
+  DCHECK_EQ(lhs->hash(), rhs->hash());
+  if (lhs->length() != rhs->length()) return false;
+  const unsigned char* l = lhs->raw_data();
+  const unsigned char* r = rhs->raw_data();
+  size_t length = rhs->length();
+  if (lhs->is_one_byte()) {
+    if (rhs->is_one_byte()) {
+      return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
+                                  reinterpret_cast<const uint8_t*>(r),
+                                  length) == 0;
+    } else {
+      return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
+                                  reinterpret_cast<const uint16_t*>(r),
+                                  length) == 0;
+    }
+  } else {
+    if (rhs->is_one_byte()) {
+      return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
+                                  reinterpret_cast<const uint8_t*>(r),
+                                  length) == 0;
+    } else {
+      return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
+                                  reinterpret_cast<const uint16_t*>(r),
+                                  length) == 0;
+    }
+  }
+}
 
 void AstConsString::Internalize(Isolate* isolate) {
   // AstRawStrings are internalized before AstConsStrings so left and right are
@@ -182,14 +214,10 @@
       DCHECK(!string_->string().is_null());
       break;
     case SYMBOL:
-      if (symbol_name_[0] == 'i') {
-        DCHECK_EQ(0, strcmp(symbol_name_, "iterator_symbol"));
-        set_value(isolate->factory()->iterator_symbol());
-      } else if (strcmp(symbol_name_, "hasInstance_symbol") == 0) {
-        set_value(isolate->factory()->has_instance_symbol());
-      } else {
-        DCHECK_EQ(0, strcmp(symbol_name_, "home_object_symbol"));
-        set_value(isolate->factory()->home_object_symbol());
+      switch (symbol_) {
+        case AstSymbol::kHomeObjectSymbol:
+          set_value(isolate->factory()->home_object_symbol());
+          break;
       }
       break;
     case NUMBER_WITH_DOT:
@@ -219,9 +247,17 @@
   }
 }
 
-
 AstRawString* AstValueFactory::GetOneByteStringInternal(
     Vector<const uint8_t> literal) {
+  if (literal.length() == 1 && IsInRange(literal[0], 'a', 'z')) {
+    int key = literal[0] - 'a';
+    if (one_character_strings_[key] == nullptr) {
+      uint32_t hash = StringHasher::HashSequentialString<uint8_t>(
+          literal.start(), literal.length(), hash_seed_);
+      one_character_strings_[key] = GetString(hash, true, literal);
+    }
+    return one_character_strings_[key];
+  }
   uint32_t hash = StringHasher::HashSequentialString<uint8_t>(
       literal.start(), literal.length(), hash_seed_);
   return GetString(hash, true, literal);
@@ -260,39 +296,6 @@
   return new_string;
 }
 
-const AstRawString* AstValueFactory::ConcatStrings(const AstRawString* left,
-                                                   const AstRawString* right) {
-  int left_length = left->length();
-  int right_length = right->length();
-  const unsigned char* left_data = left->raw_data();
-  const unsigned char* right_data = right->raw_data();
-  if (left->is_one_byte() && right->is_one_byte()) {
-    uint8_t* buffer = zone_->NewArray<uint8_t>(left_length + right_length);
-    memcpy(buffer, left_data, left_length);
-    memcpy(buffer + left_length, right_data, right_length);
-    Vector<const uint8_t> literal(buffer, left_length + right_length);
-    return GetOneByteStringInternal(literal);
-  } else {
-    uint16_t* buffer = zone_->NewArray<uint16_t>(left_length + right_length);
-    if (left->is_one_byte()) {
-      for (int i = 0; i < left_length; ++i) {
-        buffer[i] = left_data[i];
-      }
-    } else {
-      memcpy(buffer, left_data, 2 * left_length);
-    }
-    if (right->is_one_byte()) {
-      for (int i = 0; i < right_length; ++i) {
-        buffer[i + left_length] = right_data[i];
-      }
-    } else {
-      memcpy(buffer + left_length, right_data, 2 * right_length);
-    }
-    Vector<const uint16_t> literal(buffer, left_length + right_length);
-    return GetTwoByteStringInternal(literal);
-  }
-}
-
 void AstValueFactory::Internalize(Isolate* isolate) {
   // Strings need to be internalized before values, because values refer to
   // strings.
@@ -318,9 +321,8 @@
   return AddValue(value);
 }
 
-
-const AstValue* AstValueFactory::NewSymbol(const char* name) {
-  AstValue* value = new (zone_) AstValue(name);
+const AstValue* AstValueFactory::NewSymbol(AstSymbol symbol) {
+  AstValue* value = new (zone_) AstValue(symbol);
   return AddValue(value);
 }
 
@@ -379,7 +381,7 @@
   // return this AstRawString.
   AstRawString key(is_one_byte, literal_bytes, hash);
   base::HashMap::Entry* entry = string_table_.LookupOrInsert(&key, hash);
-  if (entry->value == NULL) {
+  if (entry->value == nullptr) {
     // Copy literal contents for later comparison.
     int length = literal_bytes.length();
     byte* new_literal_bytes = zone_->NewArray<byte>(length);
@@ -394,36 +396,5 @@
   return reinterpret_cast<AstRawString*>(entry->key);
 }
 
-
-bool AstValueFactory::AstRawStringCompare(void* a, void* b) {
-  const AstRawString* lhs = static_cast<AstRawString*>(a);
-  const AstRawString* rhs = static_cast<AstRawString*>(b);
-  DCHECK_EQ(lhs->hash(), rhs->hash());
-  if (lhs->length() != rhs->length()) return false;
-  const unsigned char* l = lhs->raw_data();
-  const unsigned char* r = rhs->raw_data();
-  size_t length = rhs->length();
-  if (lhs->is_one_byte()) {
-    if (rhs->is_one_byte()) {
-      return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
-                                  reinterpret_cast<const uint8_t*>(r),
-                                  length) == 0;
-    } else {
-      return CompareCharsUnsigned(reinterpret_cast<const uint8_t*>(l),
-                                  reinterpret_cast<const uint16_t*>(r),
-                                  length) == 0;
-    }
-  } else {
-    if (rhs->is_one_byte()) {
-      return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
-                                  reinterpret_cast<const uint8_t*>(r),
-                                  length) == 0;
-    } else {
-      return CompareCharsUnsigned(reinterpret_cast<const uint16_t*>(l),
-                                  reinterpret_cast<const uint16_t*>(r),
-                                  length) == 0;
-    }
-  }
-}
 }  // namespace internal
 }  // namespace v8
diff --git a/src/ast/ast-value-factory.h b/src/ast/ast-value-factory.h
index 4ce480f..c1ed7ac 100644
--- a/src/ast/ast-value-factory.h
+++ b/src/ast/ast-value-factory.h
@@ -28,9 +28,11 @@
 #ifndef V8_AST_AST_VALUE_FACTORY_H_
 #define V8_AST_AST_VALUE_FACTORY_H_
 
-#include "src/api.h"
 #include "src/base/hashmap.h"
+#include "src/conversions.h"
+#include "src/factory.h"
 #include "src/globals.h"
+#include "src/isolate.h"
 #include "src/utils.h"
 
 // AstString, AstValue and AstValueFactory are for storing strings and values
@@ -104,14 +106,17 @@
     return *c;
   }
 
+  static bool Compare(void* a, void* b);
+
   // For storing AstRawStrings in a hash map.
   uint32_t hash() const {
     return hash_;
   }
 
  private:
-  friend class AstValueFactory;
   friend class AstRawStringInternalizationKey;
+  friend class AstStringConstants;
+  friend class AstValueFactory;
 
   AstRawString(bool is_one_byte, const Vector<const byte>& literal_bytes,
                uint32_t hash)
@@ -149,19 +154,19 @@
   const AstString* right_;
 };
 
+enum class AstSymbol : uint8_t { kHomeObjectSymbol };
 
-// AstValue is either a string, a number, a string array, a boolean, or a
-// special value (null, undefined, the hole).
+// AstValue is either a string, a symbol, a number, a string array, a boolean,
+// or a special value (null, undefined, the hole).
 class AstValue : public ZoneObject {
  public:
   bool IsString() const {
     return type_ == STRING;
   }
 
-  bool IsNumber() const {
-    return type_ == NUMBER || type_ == NUMBER_WITH_DOT || type_ == SMI ||
-           type_ == SMI_WITH_DOT;
-  }
+  bool IsSymbol() const { return type_ == SYMBOL; }
+
+  bool IsNumber() const { return IsSmi() || IsHeapNumber(); }
 
   bool ContainsDot() const {
     return type_ == NUMBER_WITH_DOT || type_ == SMI_WITH_DOT;
@@ -172,20 +177,36 @@
     return string_;
   }
 
+  AstSymbol AsSymbol() const {
+    CHECK_EQ(SYMBOL, type_);
+    return symbol_;
+  }
+
   double AsNumber() const {
-    if (type_ == NUMBER || type_ == NUMBER_WITH_DOT)
-      return number_;
-    if (type_ == SMI || type_ == SMI_WITH_DOT)
-      return smi_;
+    if (IsHeapNumber()) return number_;
+    if (IsSmi()) return smi_;
     UNREACHABLE();
     return 0;
   }
 
   Smi* AsSmi() const {
-    CHECK(type_ == SMI || type_ == SMI_WITH_DOT);
+    CHECK(IsSmi());
     return Smi::FromInt(smi_);
   }
 
+  bool ToUint32(uint32_t* value) const {
+    if (IsSmi()) {
+      int num = smi_;
+      if (num < 0) return false;
+      *value = static_cast<uint32_t>(num);
+      return true;
+    }
+    if (IsHeapNumber()) {
+      return DoubleToUint32IfEqualToSelf(number_, value);
+    }
+    return false;
+  }
+
   bool EqualsString(const AstRawString* string) const {
     return type_ == STRING && string_ == string;
   }
@@ -195,6 +216,9 @@
   bool BooleanValue() const;
 
   bool IsSmi() const { return type_ == SMI || type_ == SMI_WITH_DOT; }
+  bool IsHeapNumber() const {
+    return type_ == NUMBER || type_ == NUMBER_WITH_DOT;
+  }
   bool IsFalse() const { return type_ == BOOLEAN && !bool_; }
   bool IsTrue() const { return type_ == BOOLEAN && bool_; }
   bool IsUndefined() const { return type_ == UNDEFINED; }
@@ -235,8 +259,8 @@
     string_ = s;
   }
 
-  explicit AstValue(const char* name) : type_(SYMBOL), next_(nullptr) {
-    symbol_name_ = name;
+  explicit AstValue(AstSymbol symbol) : type_(SYMBOL), next_(nullptr) {
+    symbol_ = symbol;
   }
 
   explicit AstValue(double n, bool with_dot) : next_(nullptr) {
@@ -276,11 +300,10 @@
     double number_;
     int smi_;
     bool bool_;
-    const char* symbol_name_;
+    AstSymbol symbol_;
   };
 };
 
-
 // For generating constants.
 #define STRING_CONSTANTS(F)                     \
   F(anonymous_function, "(anonymous function)") \
@@ -291,7 +314,6 @@
   F(default, "default")                         \
   F(done, "done")                               \
   F(dot, ".")                                   \
-  F(dot_class_field_init, ".class-field-init")  \
   F(dot_for, ".for")                            \
   F(dot_generator_object, ".generator_object")  \
   F(dot_iterator, ".iterator")                  \
@@ -304,6 +326,7 @@
   F(get_space, "get ")                          \
   F(length, "length")                           \
   F(let, "let")                                 \
+  F(name, "name")                               \
   F(native, "native")                           \
   F(new_target, ".new.target")                  \
   F(next, "next")                               \
@@ -320,6 +343,55 @@
   F(use_strict, "use strict")                   \
   F(value, "value")
 
+class AstStringConstants final {
+ public:
+  AstStringConstants(Isolate* isolate, uint32_t hash_seed)
+      : zone_(isolate->allocator(), ZONE_NAME),
+        string_table_(AstRawString::Compare),
+        hash_seed_(hash_seed) {
+    DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
+#define F(name, str)                                                      \
+  {                                                                       \
+    const char* data = str;                                               \
+    Vector<const uint8_t> literal(reinterpret_cast<const uint8_t*>(data), \
+                                  static_cast<int>(strlen(data)));        \
+    uint32_t hash = StringHasher::HashSequentialString<uint8_t>(          \
+        literal.start(), literal.length(), hash_seed_);                   \
+    name##_string_ = new (&zone_) AstRawString(true, literal, hash);      \
+    /* The Handle returned by the factory is located on the roots */      \
+    /* array, not on the temporary HandleScope, so this is safe.  */      \
+    name##_string_->set_string(isolate->factory()->name##_string());      \
+    base::HashMap::Entry* entry =                                         \
+        string_table_.InsertNew(name##_string_, name##_string_->hash());  \
+    DCHECK(entry->value == nullptr);                                      \
+    entry->value = reinterpret_cast<void*>(1);                            \
+  }
+    STRING_CONSTANTS(F)
+#undef F
+  }
+
+#define F(name, str) \
+  const AstRawString* name##_string() const { return name##_string_; }
+  STRING_CONSTANTS(F)
+#undef F
+
+  uint32_t hash_seed() const { return hash_seed_; }
+  const base::CustomMatcherHashMap* string_table() const {
+    return &string_table_;
+  }
+
+ private:
+  Zone zone_;
+  base::CustomMatcherHashMap string_table_;
+  uint32_t hash_seed_;
+
+#define F(name, str) AstRawString* name##_string_;
+  STRING_CONSTANTS(F)
+#undef F
+
+  DISALLOW_COPY_AND_ASSIGN(AstStringConstants);
+};
+
 #define OTHER_CONSTANTS(F) \
   F(true_value)            \
   F(false_value)           \
@@ -329,21 +401,23 @@
 
 class AstValueFactory {
  public:
-  AstValueFactory(Zone* zone, uint32_t hash_seed)
-      : string_table_(AstRawStringCompare),
+  AstValueFactory(Zone* zone, const AstStringConstants* string_constants,
+                  uint32_t hash_seed)
+      : string_table_(string_constants->string_table()),
         values_(nullptr),
-        smis_(),
         strings_(nullptr),
         strings_end_(&strings_),
+        string_constants_(string_constants),
         zone_(zone),
         hash_seed_(hash_seed) {
-#define F(name, str) name##_string_ = NULL;
-    STRING_CONSTANTS(F)
-#undef F
-#define F(name) name##_ = NULL;
+#define F(name) name##_ = nullptr;
     OTHER_CONSTANTS(F)
 #undef F
+    DCHECK_EQ(hash_seed, string_constants->hash_seed());
     std::fill(smis_, smis_ + arraysize(smis_), nullptr);
+    std::fill(one_character_strings_,
+              one_character_strings_ + arraysize(one_character_strings_),
+              nullptr);
   }
 
   Zone* zone() const { return zone_; }
@@ -361,28 +435,21 @@
   const AstRawString* GetString(Handle<String> literal);
   const AstConsString* NewConsString(const AstString* left,
                                      const AstString* right);
-  const AstRawString* ConcatStrings(const AstRawString* left,
-                                    const AstRawString* right);
 
-  void Internalize(Isolate* isolate);
+  V8_EXPORT_PRIVATE void Internalize(Isolate* isolate);
 
-#define F(name, str)                                                    \
-  const AstRawString* name##_string() {                                 \
-    if (name##_string_ == NULL) {                                       \
-      const char* data = str;                                           \
-      name##_string_ = GetOneByteString(                                \
-          Vector<const uint8_t>(reinterpret_cast<const uint8_t*>(data), \
-                                static_cast<int>(strlen(data))));       \
-    }                                                                   \
-    return name##_string_;                                              \
+#define F(name, str)                           \
+  const AstRawString* name##_string() {        \
+    return string_constants_->name##_string(); \
   }
   STRING_CONSTANTS(F)
 #undef F
 
-  const AstValue* NewString(const AstRawString* string);
+  V8_EXPORT_PRIVATE const AstValue* NewString(const AstRawString* string);
   // A JavaScript symbol (ECMA-262 edition 6).
-  const AstValue* NewSymbol(const char* name);
-  const AstValue* NewNumber(double number, bool with_dot = false);
+  const AstValue* NewSymbol(AstSymbol symbol);
+  V8_EXPORT_PRIVATE const AstValue* NewNumber(double number,
+                                              bool with_dot = false);
   const AstValue* NewSmi(uint32_t number);
   const AstValue* NewBoolean(bool b);
   const AstValue* NewStringList(ZoneList<const AstRawString*>* strings);
@@ -415,27 +482,29 @@
   AstRawString* GetString(uint32_t hash, bool is_one_byte,
                           Vector<const byte> literal_bytes);
 
-  static bool AstRawStringCompare(void* a, void* b);
-
   // All strings are copied here, one after another (no NULLs inbetween).
   base::CustomMatcherHashMap string_table_;
   // For keeping track of all AstValues and AstRawStrings we've created (so that
   // they can be internalized later).
   AstValue* values_;
 
-  AstValue* smis_[kMaxCachedSmi + 1];
   // We need to keep track of strings_ in order since cons strings require their
   // members to be internalized first.
   AstString* strings_;
   AstString** strings_end_;
+
+  // Holds constant string values which are shared across the isolate.
+  const AstStringConstants* string_constants_;
+
+  // Caches for faster access: small numbers, one character lowercase strings
+  // (for minified code).
+  AstValue* smis_[kMaxCachedSmi + 1];
+  AstRawString* one_character_strings_[26];
+
   Zone* zone_;
 
   uint32_t hash_seed_;
 
-#define F(name, str) const AstRawString* name##_string_;
-  STRING_CONSTANTS(F)
-#undef F
-
 #define F(name) AstValue* name##_;
   OTHER_CONSTANTS(F)
 #undef F
diff --git a/src/ast/ast.cc b/src/ast/ast.cc
index fc8bd8a..5705c70 100644
--- a/src/ast/ast.cc
+++ b/src/ast/ast.cc
@@ -10,11 +10,15 @@
 #include "src/ast/prettyprinter.h"
 #include "src/ast/scopes.h"
 #include "src/base/hashmap.h"
+#include "src/builtins/builtins-constructor.h"
 #include "src/builtins/builtins.h"
 #include "src/code-stubs.h"
 #include "src/contexts.h"
 #include "src/conversions.h"
+#include "src/double.h"
 #include "src/elements.h"
+#include "src/objects-inl.h"
+#include "src/objects/literal-objects.h"
 #include "src/property-details.h"
 #include "src/property.h"
 #include "src/string-stream.h"
@@ -28,6 +32,24 @@
 
 #ifdef DEBUG
 
+static const char* NameForNativeContextIntrinsicIndex(uint32_t idx) {
+  switch (idx) {
+#define NATIVE_CONTEXT_FIELDS_IDX(NAME, Type, name) \
+  case Context::NAME:                               \
+    return #name;
+
+    NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_FIELDS_IDX)
+#undef NATIVE_CONTEXT_FIELDS_IDX
+
+    default:
+      break;
+  }
+
+  return "UnknownIntrinsicIndex";
+}
+
+void AstNode::Print() { Print(Isolate::Current()); }
+
 void AstNode::Print(Isolate* isolate) {
   AstPrinter::PrintOut(isolate, this);
 }
@@ -70,6 +92,10 @@
   return IsLiteral() && AsLiteral()->raw_value()->IsSmi();
 }
 
+bool Expression::IsNumberLiteral() const {
+  return IsLiteral() && AsLiteral()->raw_value()->IsNumber();
+}
+
 bool Expression::IsStringLiteral() const {
   return IsLiteral() && AsLiteral()->raw_value()->IsString();
 }
@@ -195,50 +221,51 @@
   set_var(var);
   set_is_resolved();
   var->set_is_used();
+  if (is_assigned()) var->set_maybe_assigned();
 }
 
-
-void VariableProxy::AssignFeedbackVectorSlots(Isolate* isolate,
-                                              FeedbackVectorSpec* spec,
-                                              FeedbackVectorSlotCache* cache) {
+void VariableProxy::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                        TypeofMode typeof_mode,
+                                        FeedbackSlotCache* cache) {
   if (UsesVariableFeedbackSlot()) {
     // VariableProxies that point to the same Variable within a function can
     // make their loads from the same IC slot.
     if (var()->IsUnallocated() || var()->mode() == DYNAMIC_GLOBAL) {
-      ZoneHashMap::Entry* entry = cache->Get(var());
-      if (entry != NULL) {
-        variable_feedback_slot_ = FeedbackVectorSlot(
-            static_cast<int>(reinterpret_cast<intptr_t>(entry->value)));
+      FeedbackSlot slot = cache->Get(typeof_mode, var());
+      if (!slot.IsInvalid()) {
+        variable_feedback_slot_ = slot;
         return;
       }
-      variable_feedback_slot_ = spec->AddLoadGlobalICSlot(var()->name());
-      cache->Put(var(), variable_feedback_slot_);
+      variable_feedback_slot_ = spec->AddLoadGlobalICSlot(typeof_mode);
+      cache->Put(typeof_mode, var(), variable_feedback_slot_);
     } else {
       variable_feedback_slot_ = spec->AddLoadICSlot();
     }
   }
 }
 
-
 static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec,
-                              FeedbackVectorSlot* out_slot) {
+                              LanguageMode language_mode,
+                              FeedbackSlot* out_slot) {
   Property* property = expr->AsProperty();
   LhsKind assign_type = Property::GetAssignType(property);
   if ((assign_type == VARIABLE &&
        expr->AsVariableProxy()->var()->IsUnallocated()) ||
       assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) {
     // TODO(ishell): consider using ICSlotCache for variables here.
-    FeedbackVectorSlotKind kind = assign_type == KEYED_PROPERTY
-                                      ? FeedbackVectorSlotKind::KEYED_STORE_IC
-                                      : FeedbackVectorSlotKind::STORE_IC;
-    *out_slot = spec->AddSlot(kind);
+    if (assign_type == KEYED_PROPERTY) {
+      *out_slot = spec->AddKeyedStoreICSlot(language_mode);
+
+    } else {
+      *out_slot = spec->AddStoreICSlot(language_mode);
+    }
   }
 }
 
-void ForInStatement::AssignFeedbackVectorSlots(Isolate* isolate,
-                                               FeedbackVectorSpec* spec,
-                                               FeedbackVectorSlotCache* cache) {
-  AssignVectorSlots(each(), spec, &each_slot_);
+void ForInStatement::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                         LanguageMode language_mode,
+                                         FeedbackSlotCache* cache) {
+  AssignVectorSlots(each(), spec, language_mode, &each_slot_);
   for_in_feedback_slot_ = spec->AddGeneralSlot();
 }
 
@@ -253,17 +280,16 @@
                 StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op);
 }
 
-void Assignment::AssignFeedbackVectorSlots(Isolate* isolate,
-                                           FeedbackVectorSpec* spec,
-                                           FeedbackVectorSlotCache* cache) {
-  AssignVectorSlots(target(), spec, &slot_);
+void Assignment::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                     LanguageMode language_mode,
+                                     FeedbackSlotCache* cache) {
+  AssignVectorSlots(target(), spec, language_mode, &slot_);
 }
 
-
-void CountOperation::AssignFeedbackVectorSlots(Isolate* isolate,
-                                               FeedbackVectorSpec* spec,
-                                               FeedbackVectorSlotCache* cache) {
-  AssignVectorSlots(expression(), spec, &slot_);
+void CountOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                         LanguageMode language_mode,
+                                         FeedbackSlotCache* cache) {
+  AssignVectorSlots(expression(), spec, language_mode, &slot_);
   // Assign a slot to collect feedback about binary operations. Used only in
   // ignition. Fullcodegen uses AstId to record type feedback.
   binary_operation_slot_ = spec->AddInterpreterBinaryOpICSlot();
@@ -346,6 +372,16 @@
   }
 }
 
+FeedbackSlot LiteralProperty::GetStoreDataPropertySlot() const {
+  int offset = FunctionLiteral::NeedsHomeObject(value_) ? 1 : 0;
+  return GetSlot(offset);
+}
+
+void LiteralProperty::SetStoreDataPropertySlot(FeedbackSlot slot) {
+  int offset = FunctionLiteral::NeedsHomeObject(value_) ? 1 : 0;
+  return SetSlot(slot, offset);
+}
+
 bool LiteralProperty::NeedsSetFunctionName() const {
   return is_computed_name_ &&
          (value_->IsAnonymousFunctionDefinition() ||
@@ -360,22 +396,27 @@
       kind_(kind),
       is_static_(is_static) {}
 
-void ClassLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
-                                             FeedbackVectorSpec* spec,
-                                             FeedbackVectorSlotCache* cache) {
+void ClassLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                       LanguageMode language_mode,
+                                       FeedbackSlotCache* cache) {
   // This logic that computes the number of slots needed for vector store
-  // ICs must mirror FullCodeGenerator::VisitClassLiteral.
-  prototype_slot_ = spec->AddLoadICSlot();
+  // ICs must mirror BytecodeGenerator::VisitClassLiteral.
+  if (FunctionLiteral::NeedsHomeObject(constructor())) {
+    home_object_slot_ = spec->AddStoreICSlot(language_mode);
+  }
+
   if (NeedsProxySlot()) {
-    proxy_slot_ = spec->AddStoreICSlot();
+    proxy_slot_ = spec->AddStoreICSlot(language_mode);
   }
 
   for (int i = 0; i < properties()->length(); i++) {
     ClassLiteral::Property* property = properties()->at(i);
     Expression* value = property->value();
     if (FunctionLiteral::NeedsHomeObject(value)) {
-      property->SetSlot(spec->AddStoreICSlot());
+      property->SetSlot(spec->AddStoreICSlot(language_mode));
     }
+    property->SetStoreDataPropertySlot(
+        spec->AddStoreDataPropertyInLiteralICSlot());
   }
 }
 
@@ -392,9 +433,11 @@
 
 bool ObjectLiteral::Property::emit_store() const { return emit_store_; }
 
-void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
-                                              FeedbackVectorSpec* spec,
-                                              FeedbackVectorSlotCache* cache) {
+void ObjectLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                        LanguageMode language_mode,
+                                        FeedbackSlotCache* cache) {
+  MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, cache);
+
   // This logic that computes the number of slots needed for vector store
   // ics must mirror FullCodeGenerator::VisitObjectLiteral.
   int property_index = 0;
@@ -406,6 +449,7 @@
     Literal* key = property->key()->AsLiteral();
     Expression* value = property->value();
     switch (property->kind()) {
+      case ObjectLiteral::Property::SPREAD:
       case ObjectLiteral::Property::CONSTANT:
         UNREACHABLE();
       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
@@ -413,29 +457,29 @@
       case ObjectLiteral::Property::COMPUTED:
         // It is safe to use [[Put]] here because the boilerplate already
         // contains computed properties with an uninitialized value.
-        if (key->value()->IsInternalizedString()) {
+        if (key->IsStringLiteral()) {
           if (property->emit_store()) {
-            property->SetSlot(spec->AddStoreICSlot());
+            property->SetSlot(spec->AddStoreOwnICSlot());
             if (FunctionLiteral::NeedsHomeObject(value)) {
-              property->SetSlot(spec->AddStoreICSlot(), 1);
+              property->SetSlot(spec->AddStoreICSlot(language_mode), 1);
             }
           }
           break;
         }
         if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
-          property->SetSlot(spec->AddStoreICSlot());
+          property->SetSlot(spec->AddStoreICSlot(language_mode));
         }
         break;
       case ObjectLiteral::Property::PROTOTYPE:
         break;
       case ObjectLiteral::Property::GETTER:
         if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
-          property->SetSlot(spec->AddStoreICSlot());
+          property->SetSlot(spec->AddStoreICSlot(language_mode));
         }
         break;
       case ObjectLiteral::Property::SETTER:
         if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) {
-          property->SetSlot(spec->AddStoreICSlot());
+          property->SetSlot(spec->AddStoreICSlot(language_mode));
         }
         break;
     }
@@ -447,9 +491,11 @@
     Expression* value = property->value();
     if (property->kind() != ObjectLiteral::Property::PROTOTYPE) {
       if (FunctionLiteral::NeedsHomeObject(value)) {
-        property->SetSlot(spec->AddStoreICSlot());
+        property->SetSlot(spec->AddStoreICSlot(language_mode));
       }
     }
+    property->SetStoreDataPropertySlot(
+        spec->AddStoreDataPropertyInLiteralICSlot());
   }
 }
 
@@ -491,13 +537,8 @@
          property->kind() != ObjectLiteral::Property::PROTOTYPE;
 }
 
-
-void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
-  if (!constant_properties_.is_null()) return;
-
-  // Allocate a fixed array to hold all the constant properties.
-  Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray(
-      boilerplate_properties_ * 2, TENURED);
+void ObjectLiteral::InitDepthAndFlags() {
+  if (depth_ > 0) return;
 
   int position = 0;
   // Accumulate the value in local variables and store it at the end.
@@ -521,50 +562,43 @@
 
     MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
     if (m_literal != NULL) {
-      m_literal->BuildConstants(isolate);
+      m_literal->InitDepthAndFlags();
       if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1;
     }
 
-    // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
-    // value for COMPUTED properties, the real value is filled in at
-    // runtime. The enumeration order is maintained.
-    Handle<Object> key = property->key()->AsLiteral()->value();
-    Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
+    const AstValue* key = property->key()->AsLiteral()->raw_value();
+    Expression* value = property->value();
+
+    bool is_compile_time_value = CompileTimeValue::IsCompileTimeValue(value);
 
     // Ensure objects that may, at any point in time, contain fields with double
     // representation are always treated as nested objects. This is true for
-    // computed fields (value is undefined), and smi and double literals
-    // (value->IsNumber()).
+    // computed fields, and smi and double literals.
     // TODO(verwaest): Remove once we can store them inline.
     if (FLAG_track_double_fields &&
-        (value->IsNumber() || value->IsUninitialized(isolate))) {
+        (value->IsNumberLiteral() || !is_compile_time_value)) {
       bit_field_ = MayStoreDoublesField::update(bit_field_, true);
     }
 
-    is_simple = is_simple && !value->IsUninitialized(isolate);
+    is_simple = is_simple && is_compile_time_value;
 
     // Keep track of the number of elements in the object literal and
     // the largest element index.  If the largest element index is
     // much larger than the number of elements, creating an object
     // literal with fast elements will be a waste of space.
     uint32_t element_index = 0;
-    if (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index)) {
+    if (key->IsString() && key->AsString()->AsArrayIndex(&element_index)) {
       max_element_index = Max(element_index, max_element_index);
       elements++;
-      key = isolate->factory()->NewNumberFromUint(element_index);
-    } else if (key->ToArrayIndex(&element_index)) {
+    } else if (key->ToUint32(&element_index) && element_index != kMaxUInt32) {
       max_element_index = Max(element_index, max_element_index);
       elements++;
-    } else if (key->IsNumber()) {
-      key = isolate->factory()->NumberToString(key);
     }
 
-    // Add name, value pair to the fixed array.
-    constant_properties->set(position++, *key);
-    constant_properties->set(position++, *value);
+    // Increment the position for the key and the value.
+    position += 2;
   }
 
-  constant_properties_ = constant_properties;
   bit_field_ = FastElementsField::update(
       bit_field_,
       (max_element_index <= 32) || ((2 * elements) >= max_element_index));
@@ -574,6 +608,117 @@
   set_depth(depth_acc);
 }
 
+void ObjectLiteral::BuildConstantProperties(Isolate* isolate) {
+  if (!constant_properties_.is_null()) return;
+
+  int index_keys = 0;
+  bool has_seen_proto = false;
+  for (int i = 0; i < properties()->length(); i++) {
+    ObjectLiteral::Property* property = properties()->at(i);
+    if (!IsBoilerplateProperty(property)) {
+      has_seen_proto = true;
+      continue;
+    }
+    if (property->is_computed_name()) {
+      continue;
+    }
+
+    Handle<Object> key = property->key()->AsLiteral()->value();
+
+    uint32_t element_index = 0;
+    if (key->ToArrayIndex(&element_index) ||
+        (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index))) {
+      index_keys++;
+    }
+  }
+
+  Handle<BoilerplateDescription> constant_properties =
+      isolate->factory()->NewBoilerplateDescription(boilerplate_properties_,
+                                                    properties()->length(),
+                                                    index_keys, has_seen_proto);
+
+  int position = 0;
+  for (int i = 0; i < properties()->length(); i++) {
+    ObjectLiteral::Property* property = properties()->at(i);
+    if (!IsBoilerplateProperty(property)) {
+      continue;
+    }
+
+    if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) {
+      DCHECK(property->is_computed_name());
+      break;
+    }
+    DCHECK(!property->is_computed_name());
+
+    MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
+    if (m_literal != NULL) {
+      m_literal->BuildConstants(isolate);
+    }
+
+    // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined
+    // value for COMPUTED properties, the real value is filled in at
+    // runtime. The enumeration order is maintained.
+    Handle<Object> key = property->key()->AsLiteral()->value();
+    Handle<Object> value = GetBoilerplateValue(property->value(), isolate);
+
+    uint32_t element_index = 0;
+    if (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index)) {
+      key = isolate->factory()->NewNumberFromUint(element_index);
+    } else if (key->IsNumber() && !key->ToArrayIndex(&element_index)) {
+      key = isolate->factory()->NumberToString(key);
+    }
+
+    // Add name, value pair to the fixed array.
+    constant_properties->set(position++, *key);
+    constant_properties->set(position++, *value);
+  }
+
+  constant_properties_ = constant_properties;
+}
+
+bool ObjectLiteral::IsFastCloningSupported() const {
+  // The FastCloneShallowObject builtin doesn't copy elements, and object
+  // literals don't support copy-on-write (COW) elements for now.
+  // TODO(mvstanton): make object literals support COW elements.
+  return fast_elements() && has_shallow_properties() &&
+         properties_count() <= ConstructorBuiltinsAssembler::
+                                   kMaximumClonedShallowObjectProperties;
+}
+
+ElementsKind ArrayLiteral::constant_elements_kind() const {
+  return static_cast<ElementsKind>(constant_elements()->elements_kind());
+}
+
+void ArrayLiteral::InitDepthAndFlags() {
+  DCHECK_LT(first_spread_index_, 0);
+
+  if (depth_ > 0) return;
+
+  int constants_length = values()->length();
+
+  // Fill in the literals.
+  bool is_simple = true;
+  int depth_acc = 1;
+  int array_index = 0;
+  for (; array_index < constants_length; array_index++) {
+    Expression* element = values()->at(array_index);
+    DCHECK(!element->IsSpread());
+    MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
+    if (m_literal != NULL) {
+      m_literal->InitDepthAndFlags();
+      if (m_literal->depth() + 1 > depth_acc) {
+        depth_acc = m_literal->depth() + 1;
+      }
+    }
+
+    if (!CompileTimeValue::IsCompileTimeValue(element)) {
+      is_simple = false;
+    }
+  }
+
+  set_is_simple(is_simple);
+  set_depth(depth_acc);
+}
 
 void ArrayLiteral::BuildConstantElements(Isolate* isolate) {
   DCHECK_LT(first_spread_index_, 0);
@@ -586,8 +731,6 @@
       isolate->factory()->NewFixedArrayWithHoles(constants_length);
 
   // Fill in the literals.
-  bool is_simple = true;
-  int depth_acc = 1;
   bool is_holey = false;
   int array_index = 0;
   for (; array_index < constants_length; array_index++) {
@@ -596,9 +739,6 @@
     MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
     if (m_literal != NULL) {
       m_literal->BuildConstants(isolate);
-      if (m_literal->depth() + 1 > depth_acc) {
-        depth_acc = m_literal->depth() + 1;
-      }
     }
 
     // New handle scope here, needs to be after BuildContants().
@@ -611,7 +751,6 @@
 
     if (boilerplate_value->IsUninitialized(isolate)) {
       boilerplate_value = handle(Smi::kZero, isolate);
-      is_simple = false;
     }
 
     kind = GetMoreGeneralElementsKind(kind,
@@ -623,7 +762,7 @@
 
   // Simple and shallow arrays can be lazily copied, we transform the
   // elements array to a copy-on-write array.
-  if (is_simple && depth_acc == 1 && array_index > 0 &&
+  if (is_simple() && depth() == 1 && array_index > 0 &&
       IsFastSmiOrObjectElementsKind(kind)) {
     fixed_array->set_map(isolate->heap()->fixed_cow_array_map());
   }
@@ -637,21 +776,29 @@
     accessor->CopyElements(fixed_array, from_kind, elements, constants_length);
   }
 
-  // Remember both the literal's constant values as well as the ElementsKind
-  // in a 2-element FixedArray.
-  Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED);
-  literals->set(0, Smi::FromInt(kind));
-  literals->set(1, *elements);
+  // Remember both the literal's constant values as well as the ElementsKind.
+  Handle<ConstantElementsPair> literals =
+      isolate->factory()->NewConstantElementsPair(kind, elements);
 
   constant_elements_ = literals;
-  set_is_simple(is_simple);
-  set_depth(depth_acc);
 }
 
+bool ArrayLiteral::IsFastCloningSupported() const {
+  return depth() <= 1 &&
+         values()->length() <=
+             ConstructorBuiltinsAssembler::kMaximumClonedShallowArrayElements;
+}
 
-void ArrayLiteral::AssignFeedbackVectorSlots(Isolate* isolate,
-                                             FeedbackVectorSpec* spec,
-                                             FeedbackVectorSlotCache* cache) {
+void ArrayLiteral::RewindSpreads() {
+  values_->Rewind(first_spread_index_);
+  first_spread_index_ = -1;
+}
+
+void ArrayLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                       LanguageMode language_mode,
+                                       FeedbackSlotCache* cache) {
+  MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, cache);
+
   // This logic that computes the number of slots needed for vector store
   // ics must mirror FullCodeGenerator::VisitArrayLiteral.
   for (int array_index = 0; array_index < values()->length(); array_index++) {
@@ -661,7 +808,7 @@
 
     // We'll reuse the same literal slot for all of the non-constant
     // subexpressions that use a keyed store IC.
-    literal_slot_ = spec->AddKeyedStoreICSlot();
+    literal_slot_ = spec->AddKeyedStoreICSlot(language_mode);
     return;
   }
 }
@@ -678,6 +825,16 @@
   return isolate->factory()->uninitialized_value();
 }
 
+void MaterializedLiteral::InitDepthAndFlags() {
+  if (IsArrayLiteral()) {
+    return AsArrayLiteral()->InitDepthAndFlags();
+  }
+  if (IsObjectLiteral()) {
+    return AsObjectLiteral()->InitDepthAndFlags();
+  }
+  DCHECK(IsRegExpLiteral());
+  DCHECK_LE(1, depth());  // Depth should be initialized.
+}
 
 void MaterializedLiteral::BuildConstants(Isolate* isolate) {
   if (IsArrayLiteral()) {
@@ -687,7 +844,6 @@
     return AsObjectLiteral()->BuildConstantProperties(isolate);
   }
   DCHECK(IsRegExpLiteral());
-  DCHECK(depth() >= 1);  // Depth should be initialized.
 }
 
 
@@ -710,9 +866,9 @@
   set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id()));
 }
 
-void BinaryOperation::AssignFeedbackVectorSlots(
-    Isolate* isolate, FeedbackVectorSpec* spec,
-    FeedbackVectorSlotCache* cache) {
+void BinaryOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                          LanguageMode language_mode,
+                                          FeedbackSlotCache* cache) {
   // Feedback vector slot is only used by interpreter for binary operations.
   // Full-codegen uses AstId to record type feedback.
   switch (op()) {
@@ -722,7 +878,7 @@
     case Token::OR:
       return;
     default:
-      type_feedback_slot_ = spec->AddInterpreterBinaryOpICSlot();
+      feedback_slot_ = spec->AddInterpreterBinaryOpICSlot();
       return;
   }
 }
@@ -732,9 +888,9 @@
   return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF;
 }
 
-void CompareOperation::AssignFeedbackVectorSlots(
-    Isolate* isolate, FeedbackVectorSpec* spec,
-    FeedbackVectorSlotCache* cache_) {
+void CompareOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                           LanguageMode language_mode,
+                                           FeedbackSlotCache* cache_) {
   // Feedback vector slot is only used by interpreter for binary operations.
   // Full-codegen uses AstId to record type feedback.
   switch (op()) {
@@ -743,7 +899,7 @@
     case Token::IN:
       return;
     default:
-      type_feedback_slot_ = spec->AddInterpreterCompareICSlot();
+      feedback_slot_ = spec->AddInterpreterCompareICSlot();
   }
 }
 
@@ -892,8 +1048,9 @@
   }
 }
 
-void Call::AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                     FeedbackVectorSlotCache* cache) {
+void Call::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                               LanguageMode language_mode,
+                               FeedbackSlotCache* cache) {
   ic_slot_ = spec->AddCallICSlot();
 }
 
@@ -931,10 +1088,10 @@
       statements_(statements),
       compare_type_(AstType::None()) {}
 
-void CaseClause::AssignFeedbackVectorSlots(Isolate* isolate,
-                                           FeedbackVectorSpec* spec,
-                                           FeedbackVectorSlotCache* cache) {
-  type_feedback_slot_ = spec->AddInterpreterCompareICSlot();
+void CaseClause::AssignFeedbackSlots(FeedbackVectorSpec* spec,
+                                     LanguageMode language_mode,
+                                     FeedbackSlotCache* cache) {
+  feedback_slot_ = spec->AddInterpreterCompareICSlot();
 }
 
 uint32_t Literal::Hash() {
@@ -952,5 +1109,14 @@
          (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber());
 }
 
+const char* CallRuntime::debug_name() {
+#ifdef DEBUG
+  return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_)
+                        : function_->name;
+#else
+  return is_jsruntime() ? "(context function)" : function_->name;
+#endif  // DEBUG
+}
+
 }  // namespace internal
 }  // namespace v8
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 99e0672..90e94bb 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -14,11 +14,12 @@
 #include "src/factory.h"
 #include "src/globals.h"
 #include "src/isolate.h"
+#include "src/label.h"
 #include "src/list.h"
+#include "src/objects/literal-objects.h"
 #include "src/parsing/token.h"
 #include "src/runtime/runtime.h"
 #include "src/small-pointer-list.h"
-#include "src/utils.h"
 
 namespace v8 {
 namespace internal {
@@ -102,6 +103,7 @@
   V(SuperCallReference)         \
   V(CaseClause)                 \
   V(EmptyParentheses)           \
+  V(GetIterator)                \
   V(DoExpression)               \
   V(RewritableExpression)
 
@@ -125,27 +127,29 @@
 AST_NODE_LIST(DEF_FORWARD_DECLARATION)
 #undef DEF_FORWARD_DECLARATION
 
-
-class FeedbackVectorSlotCache {
+class FeedbackSlotCache {
  public:
-  explicit FeedbackVectorSlotCache(Zone* zone)
-      : zone_(zone),
-        hash_map_(ZoneHashMap::kDefaultHashMapCapacity,
-                  ZoneAllocationPolicy(zone)) {}
+  typedef std::pair<TypeofMode, Variable*> Key;
 
-  void Put(Variable* variable, FeedbackVectorSlot slot) {
-    ZoneHashMap::Entry* entry = hash_map_.LookupOrInsert(
-        variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
-    entry->value = reinterpret_cast<void*>(slot.ToInt());
+  explicit FeedbackSlotCache(Zone* zone) : map_(zone) {}
+
+  void Put(TypeofMode typeof_mode, Variable* variable, FeedbackSlot slot) {
+    Key key = std::make_pair(typeof_mode, variable);
+    auto entry = std::make_pair(key, slot);
+    map_.insert(entry);
   }
 
-  ZoneHashMap::Entry* Get(Variable* variable) const {
-    return hash_map_.Lookup(variable, ComputePointerHash(variable));
+  FeedbackSlot Get(TypeofMode typeof_mode, Variable* variable) const {
+    Key key = std::make_pair(typeof_mode, variable);
+    auto iter = map_.find(key);
+    if (iter != map_.end()) {
+      return iter->second;
+    }
+    return FeedbackSlot();
   }
 
  private:
-  Zone* zone_;
-  ZoneHashMap hash_map_;
+  ZoneMap<Key, FeedbackSlot> map_;
 };
 
 
@@ -154,7 +158,7 @@
   enum Flag {
     kNoFlags = 0,
     kDontSelfOptimize = 1 << 0,
-    kDontCrankshaft = 1 << 1
+    kMustUseIgnitionTurbo = 1 << 1
   };
 
   typedef base::Flags<Flag> Flags;
@@ -190,6 +194,7 @@
   int position() const { return position_; }
 
 #ifdef DEBUG
+  void Print();
   void Print(Isolate* isolate);
 #endif  // DEBUG
 
@@ -317,6 +322,9 @@
   // True iff the expression is a literal represented as a smi.
   bool IsSmiLiteral() const;
 
+  // True iff the expression is a literal represented as a number.
+  bool IsNumberLiteral() const;
+
   // True iff the expression is a string literal.
   bool IsStringLiteral() const;
 
@@ -466,9 +474,6 @@
 
   class IgnoreCompletionField
       : public BitField<bool, BreakableStatement::kNextBitFieldIndex, 1> {};
-
- protected:
-  static const uint8_t kNextBitFieldIndex = IgnoreCompletionField::kNext;
 };
 
 
@@ -484,9 +489,6 @@
   }
   bool IsAnonymousFunctionDefinition() const;
 
- protected:
-  static const uint8_t kNextBitFieldIndex = Expression::kNextBitFieldIndex;
-
  private:
   friend class AstNodeFactory;
 
@@ -518,8 +520,6 @@
   Declaration(VariableProxy* proxy, Scope* scope, int pos, NodeType type)
       : AstNode(pos, type), proxy_(proxy), scope_(scope), next_(nullptr) {}
 
-  static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex;
-
  private:
   VariableProxy* proxy_;
   // Nested scope from which the declaration originated.
@@ -734,10 +734,10 @@
   void set_subject(Expression* e) { subject_ = e; }
 
   // Type feedback information.
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
-  FeedbackVectorSlot EachFeedbackSlot() const { return each_slot_; }
-  FeedbackVectorSlot ForInFeedbackSlot() {
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
+  FeedbackSlot EachFeedbackSlot() const { return each_slot_; }
+  FeedbackSlot ForInFeedbackSlot() {
     DCHECK(!for_in_feedback_slot_.IsInvalid());
     return for_in_feedback_slot_;
   }
@@ -773,14 +773,11 @@
 
   Expression* each_;
   Expression* subject_;
-  FeedbackVectorSlot each_slot_;
-  FeedbackVectorSlot for_in_feedback_slot_;
+  FeedbackSlot each_slot_;
+  FeedbackSlot for_in_feedback_slot_;
 
   class ForInTypeField
       : public BitField<ForInType, ForEachStatement::kNextBitFieldIndex, 1> {};
-
- protected:
-  static const uint8_t kNextBitFieldIndex = ForInTypeField::kNext;
 };
 
 
@@ -826,12 +823,6 @@
   void set_result_done(Expression* e) { result_done_ = e; }
   void set_assign_each(Expression* e) { assign_each_ = e; }
 
-  BailoutId ContinueId() const { return EntryId(); }
-  BailoutId StackCheckId() const { return BackEdgeId(); }
-
-  static int num_ids() { return parent_num_ids() + 1; }
-  BailoutId BackEdgeId() const { return BailoutId(local_id(0)); }
-
  private:
   friend class AstNodeFactory;
 
@@ -842,8 +833,6 @@
         next_result_(NULL),
         result_done_(NULL),
         assign_each_(NULL) {}
-  static int parent_num_ids() { return ForEachStatement::num_ids(); }
-  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
   Variable* iterator_;
   Expression* assign_iterator_;
@@ -908,17 +897,25 @@
 
 class ReturnStatement final : public JumpStatement {
  public:
+  enum Type { kNormal, kAsyncReturn };
   Expression* expression() const { return expression_; }
 
   void set_expression(Expression* e) { expression_ = e; }
+  Type type() const { return TypeField::decode(bit_field_); }
+  bool is_async_return() const { return type() == kAsyncReturn; }
 
  private:
   friend class AstNodeFactory;
 
-  ReturnStatement(Expression* expression, int pos)
-      : JumpStatement(pos, kReturnStatement), expression_(expression) {}
+  ReturnStatement(Expression* expression, Type type, int pos)
+      : JumpStatement(pos, kReturnStatement), expression_(expression) {
+    bit_field_ |= TypeField::encode(type);
+  }
 
   Expression* expression_;
+
+  class TypeField
+      : public BitField<Type, JumpStatement::kNextBitFieldIndex, 1> {};
 };
 
 
@@ -930,30 +927,16 @@
   Statement* statement() const { return statement_; }
   void set_statement(Statement* s) { statement_ = s; }
 
-  void set_base_id(int id) { base_id_ = id; }
-  static int num_ids() { return parent_num_ids() + 2; }
-  BailoutId ToObjectId() const { return BailoutId(local_id(0)); }
-  BailoutId EntryId() const { return BailoutId(local_id(1)); }
-
  private:
   friend class AstNodeFactory;
 
   WithStatement(Scope* scope, Expression* expression, Statement* statement,
                 int pos)
       : Statement(pos, kWithStatement),
-        base_id_(BailoutId::None().ToInt()),
         scope_(scope),
         expression_(expression),
         statement_(statement) {}
 
-  static int parent_num_ids() { return 0; }
-  int base_id() const {
-    DCHECK(!BailoutId(base_id_).IsNone());
-    return base_id_;
-  }
-  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
-
-  int base_id_;
   Scope* scope_;
   Expression* expression_;
   Statement* statement_;
@@ -981,12 +964,10 @@
   // CaseClause will have both a slot in the feedback vector and the
   // TypeFeedbackId to record the type information. TypeFeedbackId is used by
   // full codegen and the feedback vector slot is used by interpreter.
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
 
-  FeedbackVectorSlot CompareOperationFeedbackSlot() {
-    return type_feedback_slot_;
-  }
+  FeedbackSlot CompareOperationFeedbackSlot() { return feedback_slot_; }
 
  private:
   friend class AstNodeFactory;
@@ -999,7 +980,7 @@
   Label body_target_;
   ZoneList<Statement*>* statements_;
   AstType* compare_type_;
-  FeedbackVectorSlot type_feedback_slot_;
+  FeedbackSlot feedback_slot_;
 };
 
 
@@ -1174,26 +1155,10 @@
 
 
 class DebuggerStatement final : public Statement {
- public:
-  void set_base_id(int id) { base_id_ = id; }
-  static int num_ids() { return parent_num_ids() + 1; }
-  BailoutId DebugBreakId() const { return BailoutId(local_id(0)); }
-
  private:
   friend class AstNodeFactory;
 
-  explicit DebuggerStatement(int pos)
-      : Statement(pos, kDebuggerStatement),
-        base_id_(BailoutId::None().ToInt()) {}
-
-  static int parent_num_ids() { return 0; }
-  int base_id() const {
-    DCHECK(!BailoutId(base_id_).IsNone());
-    return base_id_;
-  }
-  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
-
-  int base_id_;
+  explicit DebuggerStatement(int pos) : Statement(pos, kDebuggerStatement) {}
 };
 
 
@@ -1212,22 +1177,15 @@
  public:
   Statement* statement() const { return statement_; }
   void set_statement(Statement* statement) { statement_ = statement; }
-  Scope* scope() const { return scope_; }
-  SloppyBlockFunctionStatement* next() { return next_; }
-  void set_next(SloppyBlockFunctionStatement* next) { next_ = next; }
 
  private:
   friend class AstNodeFactory;
 
-  SloppyBlockFunctionStatement(Statement* statement, Scope* scope)
+  explicit SloppyBlockFunctionStatement(Statement* statement)
       : Statement(kNoSourcePosition, kSloppyBlockFunctionStatement),
-        statement_(statement),
-        scope_(scope),
-        next_(nullptr) {}
+        statement_(statement) {}
 
   Statement* statement_;
-  Scope* const scope_;
-  SloppyBlockFunctionStatement* next_;
 };
 
 
@@ -1275,32 +1233,32 @@
   const AstValue* value_;
 };
 
-
-class AstLiteralReindexer;
-
-// Base class for literals that needs space in the corresponding JSFunction.
+// Base class for literals that need space in the type feedback vector.
 class MaterializedLiteral : public Expression {
  public:
-  int literal_index() { return literal_index_; }
-
   int depth() const {
     // only callable after initialization.
     DCHECK(depth_ >= 1);
     return depth_;
   }
 
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache) {
+    literal_slot_ = spec->AddLiteralSlot();
+  }
+
+  FeedbackSlot literal_slot() const { return literal_slot_; }
+
  private:
   int depth_ : 31;
-  int literal_index_;
-
-  friend class AstLiteralReindexer;
+  FeedbackSlot literal_slot_;
 
   class IsSimpleField
       : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
 
  protected:
-  MaterializedLiteral(int literal_index, int pos, NodeType type)
-      : Expression(pos, type), depth_(0), literal_index_(literal_index) {
+  MaterializedLiteral(int pos, NodeType type)
+      : Expression(pos, type), depth_(0) {
     bit_field_ |= IsSimpleField::encode(false);
   }
 
@@ -1317,6 +1275,9 @@
     depth_ = depth;
   }
 
+  // Populate the depth field and any flags the literal has.
+  void InitDepthAndFlags();
+
   // Populate the constant properties/elements fixed array.
   void BuildConstants(Isolate* isolate);
   friend class ArrayLiteral;
@@ -1342,16 +1303,20 @@
 
   bool is_computed_name() const { return is_computed_name_; }
 
-  FeedbackVectorSlot GetSlot(int offset = 0) const {
+  FeedbackSlot GetSlot(int offset = 0) const {
     DCHECK_LT(offset, static_cast<int>(arraysize(slots_)));
     return slots_[offset];
   }
 
-  void SetSlot(FeedbackVectorSlot slot, int offset = 0) {
+  FeedbackSlot GetStoreDataPropertySlot() const;
+
+  void SetSlot(FeedbackSlot slot, int offset = 0) {
     DCHECK_LT(offset, static_cast<int>(arraysize(slots_)));
     slots_[offset] = slot;
   }
 
+  void SetStoreDataPropertySlot(FeedbackSlot slot);
+
   bool NeedsSetFunctionName() const;
 
  protected:
@@ -1360,7 +1325,7 @@
 
   Expression* key_;
   Expression* value_;
-  FeedbackVectorSlot slots_[2];
+  FeedbackSlot slots_[2];
   bool is_computed_name_;
 };
 
@@ -1374,8 +1339,9 @@
     COMPUTED,              // Property with computed value (execution time).
     MATERIALIZED_LITERAL,  // Property value is a materialized literal.
     GETTER,
-    SETTER,    // Property is an accessor function.
-    PROTOTYPE  // Property is __proto__.
+    SETTER,     // Property is an accessor function.
+    PROTOTYPE,  // Property is __proto__.
+    SPREAD
   };
 
   Kind kind() const { return kind_; }
@@ -1411,7 +1377,8 @@
  public:
   typedef ObjectLiteralProperty Property;
 
-  Handle<FixedArray> constant_properties() const {
+  Handle<BoilerplateDescription> constant_properties() const {
+    DCHECK(!constant_properties_.is_null());
     return constant_properties_;
   }
   int properties_count() const { return boilerplate_properties_; }
@@ -1424,10 +1391,25 @@
   bool has_shallow_properties() const {
     return depth() == 1 && !has_elements() && !may_store_doubles();
   }
+  bool has_rest_property() const {
+    return HasRestPropertyField::decode(bit_field_);
+  }
 
   // Decide if a property should be in the object boilerplate.
   static bool IsBoilerplateProperty(Property* property);
 
+  // Populate the depth field and flags.
+  void InitDepthAndFlags();
+
+  // Get the constant properties fixed array, populating it if necessary.
+  Handle<BoilerplateDescription> GetOrBuildConstantProperties(
+      Isolate* isolate) {
+    if (constant_properties_.is_null()) {
+      BuildConstantProperties(isolate);
+    }
+    return constant_properties();
+  }
+
   // Populate the constant properties fixed array.
   void BuildConstantProperties(Isolate* isolate);
 
@@ -1436,6 +1418,9 @@
   // marked expressions, no store code is emitted.
   void CalculateEmitStore(Zone* zone);
 
+  // Determines whether the {FastCloneShallowObject} builtin can be used.
+  bool IsFastCloningSupported() const;
+
   // Assemble bitfield of flags for the CreateObjectLiteral helper.
   int ComputeFlags(bool disable_mementos = false) const {
     int flags = fast_elements() ? kFastElements : kNoFlags;
@@ -1452,7 +1437,8 @@
     kNoFlags = 0,
     kFastElements = 1,
     kShallowProperties = 1 << 1,
-    kDisableMementos = 1 << 2
+    kDisableMementos = 1 << 2,
+    kHasRestProperty = 1 << 3,
   };
 
   struct Accessors: public ZoneObject {
@@ -1465,43 +1451,37 @@
   BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); }
 
   // Return an AST id for a property that is used in simulate instructions.
-  BailoutId GetIdForPropertyName(int i) {
-    return BailoutId(local_id(2 * i + 1));
-  }
-  BailoutId GetIdForPropertySet(int i) {
-    return BailoutId(local_id(2 * i + 2));
-  }
+  BailoutId GetIdForPropertySet(int i) { return BailoutId(local_id(i + 1)); }
 
   // Unlike other AST nodes, this number of bailout IDs allocated for an
   // ObjectLiteral can vary, so num_ids() is not a static method.
-  int num_ids() const {
-    return parent_num_ids() + 1 + 2 * properties()->length();
-  }
+  int num_ids() const { return parent_num_ids() + 1 + properties()->length(); }
 
   // Object literals need one feedback slot for each non-trivial value, as well
   // as some slots for home objects.
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
 
  private:
   friend class AstNodeFactory;
 
-  ObjectLiteral(ZoneList<Property*>* properties, int literal_index,
-                uint32_t boilerplate_properties, int pos)
-      : MaterializedLiteral(literal_index, pos, kObjectLiteral),
+  ObjectLiteral(ZoneList<Property*>* properties,
+                uint32_t boilerplate_properties, int pos,
+                bool has_rest_property)
+      : MaterializedLiteral(pos, kObjectLiteral),
         boilerplate_properties_(boilerplate_properties),
         properties_(properties) {
     bit_field_ |= FastElementsField::encode(false) |
                   HasElementsField::encode(false) |
-                  MayStoreDoublesField::encode(false);
+                  MayStoreDoublesField::encode(false) |
+                  HasRestPropertyField::encode(has_rest_property);
   }
 
   static int parent_num_ids() { return MaterializedLiteral::num_ids(); }
   int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
   uint32_t boilerplate_properties_;
-  FeedbackVectorSlot slot_;
-  Handle<FixedArray> constant_properties_;
+  Handle<BoilerplateDescription> constant_properties_;
   ZoneList<Property*>* properties_;
 
   class FastElementsField
@@ -1510,9 +1490,8 @@
   };
   class MayStoreDoublesField
       : public BitField<bool, HasElementsField::kNext, 1> {};
-
- protected:
-  static const uint8_t kNextBitFieldIndex = MayStoreDoublesField::kNext;
+  class HasRestPropertyField
+      : public BitField<bool, MayStoreDoublesField::kNext, 1> {};
 };
 
 
@@ -1543,14 +1522,14 @@
 class RegExpLiteral final : public MaterializedLiteral {
  public:
   Handle<String> pattern() const { return pattern_->string(); }
+  const AstRawString* raw_pattern() const { return pattern_; }
   int flags() const { return flags_; }
 
  private:
   friend class AstNodeFactory;
 
-  RegExpLiteral(const AstRawString* pattern, int flags, int literal_index,
-                int pos)
-      : MaterializedLiteral(literal_index, pos, kRegExpLiteral),
+  RegExpLiteral(const AstRawString* pattern, int flags, int pos)
+      : MaterializedLiteral(pos, kRegExpLiteral),
         flags_(flags),
         pattern_(pattern) {
     set_depth(1);
@@ -1565,12 +1544,10 @@
 // for minimizing the work when constructing it at runtime.
 class ArrayLiteral final : public MaterializedLiteral {
  public:
-  Handle<FixedArray> constant_elements() const { return constant_elements_; }
-  ElementsKind constant_elements_kind() const {
-    DCHECK_EQ(2, constant_elements_->length());
-    return static_cast<ElementsKind>(
-        Smi::cast(constant_elements_->get(0))->value());
+  Handle<ConstantElementsPair> constant_elements() const {
+    return constant_elements_;
   }
+  ElementsKind constant_elements_kind() const;
 
   ZoneList<Expression*>* values() const { return values_; }
 
@@ -1583,9 +1560,23 @@
   // ArrayLiteral can vary, so num_ids() is not a static method.
   int num_ids() const { return parent_num_ids() + 1 + values()->length(); }
 
+  // Populate the depth field and flags.
+  void InitDepthAndFlags();
+
+  // Get the constant elements fixed array, populating it if necessary.
+  Handle<ConstantElementsPair> GetOrBuildConstantElements(Isolate* isolate) {
+    if (constant_elements_.is_null()) {
+      BuildConstantElements(isolate);
+    }
+    return constant_elements();
+  }
+
   // Populate the constant elements fixed array.
   void BuildConstantElements(Isolate* isolate);
 
+  // Determines whether the {FastCloneShallowArray} builtin can be used.
+  bool IsFastCloningSupported() const;
+
   // Assemble bitfield of flags for the CreateArrayLiteral helper.
   int ComputeFlags(bool disable_mementos = false) const {
     int flags = depth() == 1 ? kShallowElements : kNoFlags;
@@ -1603,10 +1594,7 @@
   ZoneList<Expression*>::iterator EndValue() const { return values_->end(); }
 
   // Rewind an array literal omitting everything from the first spread on.
-  void RewindSpreads() {
-    values_->Rewind(first_spread_index_);
-    first_spread_index_ = -1;
-  }
+  void RewindSpreads();
 
   enum Flags {
     kNoFlags = 0,
@@ -1614,16 +1602,15 @@
     kDisableMementos = 1 << 1
   };
 
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
-  FeedbackVectorSlot LiteralFeedbackSlot() const { return literal_slot_; }
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
+  FeedbackSlot LiteralFeedbackSlot() const { return literal_slot_; }
 
  private:
   friend class AstNodeFactory;
 
-  ArrayLiteral(ZoneList<Expression*>* values, int first_spread_index,
-               int literal_index, int pos)
-      : MaterializedLiteral(literal_index, pos, kArrayLiteral),
+  ArrayLiteral(ZoneList<Expression*>* values, int first_spread_index, int pos)
+      : MaterializedLiteral(pos, kArrayLiteral),
         first_spread_index_(first_spread_index),
         values_(values) {}
 
@@ -1631,8 +1618,8 @@
   int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
   int first_spread_index_;
-  FeedbackVectorSlot literal_slot_;
-  Handle<FixedArray> constant_elements_;
+  FeedbackSlot literal_slot_;
+  Handle<ConstantElementsPair> constant_elements_;
   ZoneList<Expression*>* values_;
 };
 
@@ -1663,6 +1650,9 @@
   bool is_assigned() const { return IsAssignedField::decode(bit_field_); }
   void set_is_assigned() {
     bit_field_ = IsAssignedField::update(bit_field_, true);
+    if (is_resolved()) {
+      var()->set_maybe_assigned();
+    }
   }
 
   bool is_resolved() const { return IsResolvedField::decode(bit_field_); }
@@ -1690,10 +1680,10 @@
     return var()->IsUnallocated() || var()->IsLookupSlot();
   }
 
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, TypeofMode typeof_mode,
+                           FeedbackSlotCache* cache);
 
-  FeedbackVectorSlot VariableFeedbackSlot() { return variable_feedback_slot_; }
+  FeedbackSlot VariableFeedbackSlot() { return variable_feedback_slot_; }
 
   static int num_ids() { return parent_num_ids() + 1; }
   BailoutId BeforeId() const { return BailoutId(local_id(0)); }
@@ -1719,7 +1709,7 @@
   class HoleCheckModeField
       : public BitField<HoleCheckMode, IsNewTargetField::kNext, 1> {};
 
-  FeedbackVectorSlot variable_feedback_slot_;
+  FeedbackSlot variable_feedback_slot_;
   union {
     const AstRawString* raw_name_;  // if !is_resolved_
     Variable* var_;                 // if is_resolved_
@@ -1786,17 +1776,16 @@
 
   bool IsSuperAccess() { return obj()->IsSuperPropertyReference(); }
 
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache) {
-    FeedbackVectorSlotKind kind = key()->IsPropertyName()
-                                      ? FeedbackVectorSlotKind::LOAD_IC
-                                      : FeedbackVectorSlotKind::KEYED_LOAD_IC;
-    property_feedback_slot_ = spec->AddSlot(kind);
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache) {
+    if (key()->IsPropertyName()) {
+      property_feedback_slot_ = spec->AddLoadICSlot();
+    } else {
+      property_feedback_slot_ = spec->AddKeyedLoadICSlot();
+    }
   }
 
-  FeedbackVectorSlot PropertyFeedbackSlot() const {
-    return property_feedback_slot_;
-  }
+  FeedbackSlot PropertyFeedbackSlot() const { return property_feedback_slot_; }
 
   // Returns the properties assign type.
   static LhsKind GetAssignType(Property* property) {
@@ -1829,7 +1818,7 @@
   class InlineCacheStateField
       : public BitField<InlineCacheState, KeyTypeField::kNext, 4> {};
 
-  FeedbackVectorSlot property_feedback_slot_;
+  FeedbackSlot property_feedback_slot_;
   Expression* obj_;
   Expression* key_;
   SmallMapList receiver_types_;
@@ -1844,10 +1833,10 @@
   void set_expression(Expression* e) { expression_ = e; }
 
   // Type feedback information.
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
 
-  FeedbackVectorSlot CallFeedbackICSlot() const { return ic_slot_; }
+  FeedbackSlot CallFeedbackICSlot() const { return ic_slot_; }
 
   SmallMapList* GetReceiverTypes() {
     if (expression()->IsProperty()) {
@@ -1876,11 +1865,9 @@
     allocation_site_ = site;
   }
 
-  static int num_ids() { return parent_num_ids() + 4; }
+  static int num_ids() { return parent_num_ids() + 2; }
   BailoutId ReturnId() const { return BailoutId(local_id(0)); }
-  BailoutId EvalId() const { return BailoutId(local_id(1)); }
-  BailoutId LookupId() const { return BailoutId(local_id(2)); }
-  BailoutId CallId() const { return BailoutId(local_id(3)); }
+  BailoutId CallId() const { return BailoutId(local_id(1)); }
 
   bool is_uninitialized() const {
     return IsUninitializedField::decode(bit_field_);
@@ -1899,6 +1886,10 @@
   }
   void MarkTail() { bit_field_ = IsTailField::update(bit_field_, true); }
 
+  bool only_last_arg_is_spread() {
+    return !arguments_->is_empty() && arguments_->last()->IsSpread();
+  }
+
   enum CallType {
     GLOBAL_CALL,
     WITH_CALL,
@@ -1948,7 +1939,7 @@
   class IsTailField : public BitField<bool, IsUninitializedField::kNext, 1> {};
   class IsPossiblyEvalField : public BitField<bool, IsTailField::kNext, 1> {};
 
-  FeedbackVectorSlot ic_slot_;
+  FeedbackSlot ic_slot_;
   Expression* expression_;
   ZoneList<Expression*>* arguments_;
   Handle<JSFunction> target_;
@@ -1964,14 +1955,14 @@
   void set_expression(Expression* e) { expression_ = e; }
 
   // Type feedback information.
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache) {
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache) {
     // CallNew stores feedback in the exact same way as Call. We can
     // piggyback on the type feedback infrastructure for calls.
     callnew_feedback_slot_ = spec->AddCallICSlot();
   }
 
-  FeedbackVectorSlot CallNewFeedbackSlot() {
+  FeedbackSlot CallNewFeedbackSlot() {
     DCHECK(!callnew_feedback_slot_.IsInvalid());
     return callnew_feedback_slot_;
   }
@@ -1998,6 +1989,10 @@
     set_is_monomorphic(true);
   }
 
+  bool only_last_arg_is_spread() {
+    return !arguments_->is_empty() && arguments_->last()->IsSpread();
+  }
+
  private:
   friend class AstNodeFactory;
 
@@ -2011,7 +2006,7 @@
   static int parent_num_ids() { return Expression::num_ids(); }
   int local_id(int n) const { return base_id() + parent_num_ids() + n; }
 
-  FeedbackVectorSlot callnew_feedback_slot_;
+  FeedbackSlot callnew_feedback_slot_;
   Expression* expression_;
   ZoneList<Expression*>* arguments_;
   Handle<JSFunction> target_;
@@ -2046,10 +2041,7 @@
 
   static int num_ids() { return parent_num_ids() + 1; }
   BailoutId CallId() { return BailoutId(local_id(0)); }
-
-  const char* debug_name() {
-    return is_jsruntime() ? "(context function)" : function_->name;
-  }
+  const char* debug_name();
 
  private:
   friend class AstNodeFactory;
@@ -2138,12 +2130,10 @@
   // BinaryOperation will have both a slot in the feedback vector and the
   // TypeFeedbackId to record the type information. TypeFeedbackId is used
   // by full codegen and the feedback vector slot is used by interpreter.
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
 
-  FeedbackVectorSlot BinaryOperationFeedbackSlot() const {
-    return type_feedback_slot_;
-  }
+  FeedbackSlot BinaryOperationFeedbackSlot() const { return feedback_slot_; }
 
   TypeFeedbackId BinaryOperationFeedbackId() const {
     return TypeFeedbackId(local_id(1));
@@ -2181,7 +2171,7 @@
   Expression* left_;
   Expression* right_;
   Handle<AllocationSite> allocation_site_;
-  FeedbackVectorSlot type_feedback_slot_;
+  FeedbackSlot feedback_slot_;
 
   class OperatorField
       : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
@@ -2227,13 +2217,13 @@
   }
 
   // Feedback slot for binary operation is only used by ignition.
-  FeedbackVectorSlot CountBinaryOpFeedbackSlot() const {
+  FeedbackSlot CountBinaryOpFeedbackSlot() const {
     return binary_operation_slot_;
   }
 
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
-  FeedbackVectorSlot CountSlot() const { return slot_; }
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
+  FeedbackSlot CountSlot() const { return slot_; }
 
  private:
   friend class AstNodeFactory;
@@ -2255,8 +2245,8 @@
       : public BitField<KeyedAccessStoreMode, KeyTypeField::kNext, 3> {};
   class TokenField : public BitField<Token::Value, StoreModeField::kNext, 7> {};
 
-  FeedbackVectorSlot slot_;
-  FeedbackVectorSlot binary_operation_slot_;
+  FeedbackSlot slot_;
+  FeedbackSlot binary_operation_slot_;
   AstType* type_;
   Expression* expression_;
   SmallMapList receiver_types_;
@@ -2283,12 +2273,10 @@
   // CompareOperation will have both a slot in the feedback vector and the
   // TypeFeedbackId to record the type information. TypeFeedbackId is used
   // by full codegen and the feedback vector slot is used by interpreter.
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
 
-  FeedbackVectorSlot CompareOperationFeedbackSlot() const {
-    return type_feedback_slot_;
-  }
+  FeedbackSlot CompareOperationFeedbackSlot() const { return feedback_slot_; }
 
   // Match special cases.
   bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
@@ -2315,7 +2303,7 @@
   Expression* right_;
 
   AstType* combined_type_;
-  FeedbackVectorSlot type_feedback_slot_;
+  FeedbackSlot feedback_slot_;
   class OperatorField
       : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
 };
@@ -2429,9 +2417,9 @@
     bit_field_ = StoreModeField::update(bit_field_, mode);
   }
 
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
-  FeedbackVectorSlot AssignmentSlot() const { return slot_; }
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
+  FeedbackSlot AssignmentSlot() const { return slot_; }
 
  private:
   friend class AstNodeFactory;
@@ -2449,7 +2437,7 @@
       : public BitField<KeyedAccessStoreMode, KeyTypeField::kNext, 3> {};
   class TokenField : public BitField<Token::Value, StoreModeField::kNext, 7> {};
 
-  FeedbackVectorSlot slot_;
+  FeedbackSlot slot_;
   Expression* target_;
   Expression* value_;
   BinaryOperation* binary_operation_;
@@ -2571,6 +2559,8 @@
     kAccessorOrMethod
   };
 
+  enum IdType { kIdTypeInvalid = -1, kIdTypeTopLevel = 0 };
+
   enum ParameterFlag { kNoDuplicateParameters, kHasDuplicateParameters };
 
   enum EagerCompileHint { kShouldEagerCompile, kShouldLazyCompile };
@@ -2594,9 +2584,15 @@
   }
   LanguageMode language_mode() const;
 
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache) {
+    literal_feedback_slot_ = spec->AddCreateClosureSlot();
+  }
+
+  FeedbackSlot LiteralFeedbackSlot() const { return literal_feedback_slot_; }
+
   static bool NeedsHomeObject(Expression* expr);
 
-  int materialized_literal_count() { return materialized_literal_count_; }
   int expected_property_count() { return expected_property_count_; }
   int parameter_count() { return parameter_count_; }
   int function_length() { return function_length_; }
@@ -2644,8 +2640,6 @@
     return HasDuplicateParameters::decode(bit_field_);
   }
 
-  bool is_function() const { return IsFunction::decode(bit_field_); }
-
   // This is used as a heuristic on when to eagerly compile a function
   // literal. We consider the following constructs as hints that the
   // function will be called immediately:
@@ -2691,38 +2685,27 @@
   int yield_count() { return yield_count_; }
   void set_yield_count(int yield_count) { yield_count_ = yield_count; }
 
-  bool requires_class_field_init() {
-    return RequiresClassFieldInit::decode(bit_field_);
-  }
-  void set_requires_class_field_init(bool requires_class_field_init) {
-    bit_field_ =
-        RequiresClassFieldInit::update(bit_field_, requires_class_field_init);
-  }
-  bool is_class_field_initializer() {
-    return IsClassFieldInitializer::decode(bit_field_);
-  }
-  void set_is_class_field_initializer(bool is_class_field_initializer) {
-    bit_field_ =
-        IsClassFieldInitializer::update(bit_field_, is_class_field_initializer);
-  }
-
   int return_position() {
     return std::max(start_position(), end_position() - (has_braces_ ? 1 : 0));
   }
 
+  int function_literal_id() const { return function_literal_id_; }
+  void set_function_literal_id(int function_literal_id) {
+    function_literal_id_ = function_literal_id;
+  }
+
  private:
   friend class AstNodeFactory;
 
   FunctionLiteral(Zone* zone, const AstString* name,
                   AstValueFactory* ast_value_factory, DeclarationScope* scope,
-                  ZoneList<Statement*>* body, int materialized_literal_count,
-                  int expected_property_count, int parameter_count,
-                  int function_length, FunctionType function_type,
+                  ZoneList<Statement*>* body, int expected_property_count,
+                  int parameter_count, int function_length,
+                  FunctionType function_type,
                   ParameterFlag has_duplicate_parameters,
                   EagerCompileHint eager_compile_hint, int position,
-                  bool is_function, bool has_braces)
+                  bool has_braces, int function_literal_id)
       : Expression(position, kFunctionLiteral),
-        materialized_literal_count_(materialized_literal_count),
         expected_property_count_(expected_property_count),
         parameter_count_(parameter_count),
         function_length_(function_length),
@@ -2733,16 +2716,14 @@
         scope_(scope),
         body_(body),
         raw_inferred_name_(ast_value_factory->empty_string()),
-        ast_properties_(zone) {
-    bit_field_ |=
-        FunctionTypeBits::encode(function_type) | Pretenure::encode(false) |
-        HasDuplicateParameters::encode(has_duplicate_parameters ==
-                                       kHasDuplicateParameters) |
-        IsFunction::encode(is_function) |
-        RequiresClassFieldInit::encode(false) |
-        ShouldNotBeUsedOnceHintField::encode(false) |
-        DontOptimizeReasonField::encode(kNoReason) |
-        IsClassFieldInitializer::encode(false);
+        ast_properties_(zone),
+        function_literal_id_(function_literal_id) {
+    bit_field_ |= FunctionTypeBits::encode(function_type) |
+                  Pretenure::encode(false) |
+                  HasDuplicateParameters::encode(has_duplicate_parameters ==
+                                                 kHasDuplicateParameters) |
+                  ShouldNotBeUsedOnceHintField::encode(false) |
+                  DontOptimizeReasonField::encode(kNoReason);
     if (eager_compile_hint == kShouldEagerCompile) SetShouldEagerCompile();
   }
 
@@ -2750,17 +2731,12 @@
       : public BitField<FunctionType, Expression::kNextBitFieldIndex, 2> {};
   class Pretenure : public BitField<bool, FunctionTypeBits::kNext, 1> {};
   class HasDuplicateParameters : public BitField<bool, Pretenure::kNext, 1> {};
-  class IsFunction : public BitField<bool, HasDuplicateParameters::kNext, 1> {};
   class ShouldNotBeUsedOnceHintField
-      : public BitField<bool, IsFunction::kNext, 1> {};
-  class RequiresClassFieldInit
-      : public BitField<bool, ShouldNotBeUsedOnceHintField::kNext, 1> {};
-  class IsClassFieldInitializer
-      : public BitField<bool, RequiresClassFieldInit::kNext, 1> {};
+      : public BitField<bool, HasDuplicateParameters::kNext, 1> {};
   class DontOptimizeReasonField
-      : public BitField<BailoutReason, IsClassFieldInitializer::kNext, 8> {};
+      : public BitField<BailoutReason, ShouldNotBeUsedOnceHintField::kNext, 8> {
+  };
 
-  int materialized_literal_count_;
   int expected_property_count_;
   int parameter_count_;
   int function_length_;
@@ -2774,6 +2750,8 @@
   const AstString* raw_inferred_name_;
   Handle<String> inferred_name_;
   AstProperties ast_properties_;
+  int function_literal_id_;
+  FeedbackSlot literal_feedback_slot_;
 };
 
 // Property is used for passing information
@@ -2808,62 +2786,55 @@
   ZoneList<Property*>* properties() const { return properties_; }
   int start_position() const { return position(); }
   int end_position() const { return end_position_; }
-
-  VariableProxy* static_initializer_proxy() const {
-    return static_initializer_proxy_;
+  bool has_name_static_property() const {
+    return HasNameStaticProperty::decode(bit_field_);
   }
-  void set_static_initializer_proxy(VariableProxy* proxy) {
-    static_initializer_proxy_ = proxy;
+  bool has_static_computed_names() const {
+    return HasStaticComputedNames::decode(bit_field_);
   }
 
-  BailoutId CreateLiteralId() const { return BailoutId(local_id(0)); }
-  BailoutId PrototypeId() { return BailoutId(local_id(1)); }
-
-  // Return an AST id for a property that is used in simulate instructions.
-  BailoutId GetIdForProperty(int i) { return BailoutId(local_id(i + 2)); }
-
-  // Unlike other AST nodes, this number of bailout IDs allocated for an
-  // ClassLiteral can vary, so num_ids() is not a static method.
-  int num_ids() const { return parent_num_ids() + 2 + properties()->length(); }
-
   // Object literals need one feedback slot for each non-trivial value, as well
   // as some slots for home objects.
-  void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
-                                 FeedbackVectorSlotCache* cache);
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache);
 
   bool NeedsProxySlot() const {
     return class_variable_proxy() != nullptr &&
            class_variable_proxy()->var()->IsUnallocated();
   }
 
-  FeedbackVectorSlot PrototypeSlot() const { return prototype_slot_; }
-  FeedbackVectorSlot ProxySlot() const { return proxy_slot_; }
+  FeedbackSlot HomeObjectSlot() const { return home_object_slot_; }
+  FeedbackSlot ProxySlot() const { return proxy_slot_; }
 
  private:
   friend class AstNodeFactory;
 
   ClassLiteral(VariableProxy* class_variable_proxy, Expression* extends,
                FunctionLiteral* constructor, ZoneList<Property*>* properties,
-               int start_position, int end_position)
+               int start_position, int end_position,
+               bool has_name_static_property, bool has_static_computed_names)
       : Expression(start_position, kClassLiteral),
         end_position_(end_position),
         class_variable_proxy_(class_variable_proxy),
         extends_(extends),
         constructor_(constructor),
-        properties_(properties),
-        static_initializer_proxy_(nullptr) {}
-
-  static int parent_num_ids() { return Expression::num_ids(); }
-  int local_id(int n) const { return base_id() + parent_num_ids() + n; }
+        properties_(properties) {
+    bit_field_ |= HasNameStaticProperty::encode(has_name_static_property) |
+                  HasStaticComputedNames::encode(has_static_computed_names);
+  }
 
   int end_position_;
-  FeedbackVectorSlot prototype_slot_;
-  FeedbackVectorSlot proxy_slot_;
+  FeedbackSlot home_object_slot_;
+  FeedbackSlot proxy_slot_;
   VariableProxy* class_variable_proxy_;
   Expression* extends_;
   FunctionLiteral* constructor_;
   ZoneList<Property*>* properties_;
-  VariableProxy* static_initializer_proxy_;
+
+  class HasNameStaticProperty
+      : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
+  class HasStaticComputedNames
+      : public BitField<bool, HasNameStaticProperty::kNext, 1> {};
 };
 
 
@@ -2871,6 +2842,14 @@
  public:
   Handle<String> name() const { return name_->string(); }
   v8::Extension* extension() const { return extension_; }
+  FeedbackSlot LiteralFeedbackSlot() const { return literal_feedback_slot_; }
+
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache) {
+    // TODO(mvstanton): The FeedbackSlotCache can be adapted
+    // to always return the same slot for this case.
+    literal_feedback_slot_ = spec->AddCreateClosureSlot();
+  }
 
  private:
   friend class AstNodeFactory;
@@ -2883,6 +2862,7 @@
 
   const AstRawString* name_;
   v8::Extension* extension_;
+  FeedbackSlot literal_feedback_slot_;
 };
 
 
@@ -2955,7 +2935,59 @@
   explicit EmptyParentheses(int pos) : Expression(pos, kEmptyParentheses) {}
 };
 
+// Represents the spec operation `GetIterator()`
+// (defined at https://tc39.github.io/ecma262/#sec-getiterator). Ignition
+// desugars this into a LoadIC / JSLoadNamed, CallIC, and a type-check to
+// validate return value of the Symbol.iterator() call.
+enum class IteratorType { kNormal, kAsync };
+class GetIterator final : public Expression {
+ public:
+  IteratorType hint() const { return hint_; }
 
+  Expression* iterable() const { return iterable_; }
+  void set_iterable(Expression* iterable) { iterable_ = iterable; }
+
+  static int num_ids() { return parent_num_ids(); }
+
+  void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
+                           FeedbackSlotCache* cache) {
+    iterator_property_feedback_slot_ = spec->AddLoadICSlot();
+    iterator_call_feedback_slot_ = spec->AddCallICSlot();
+    if (hint() == IteratorType::kAsync) {
+      async_iterator_property_feedback_slot_ = spec->AddLoadICSlot();
+      async_iterator_call_feedback_slot_ = spec->AddCallICSlot();
+    }
+  }
+
+  FeedbackSlot IteratorPropertyFeedbackSlot() const {
+    return iterator_property_feedback_slot_;
+  }
+
+  FeedbackSlot IteratorCallFeedbackSlot() const {
+    return iterator_call_feedback_slot_;
+  }
+
+  FeedbackSlot AsyncIteratorPropertyFeedbackSlot() const {
+    return async_iterator_property_feedback_slot_;
+  }
+
+  FeedbackSlot AsyncIteratorCallFeedbackSlot() const {
+    return async_iterator_call_feedback_slot_;
+  }
+
+ private:
+  friend class AstNodeFactory;
+
+  explicit GetIterator(Expression* iterable, IteratorType hint, int pos)
+      : Expression(pos, kGetIterator), hint_(hint), iterable_(iterable) {}
+
+  IteratorType hint_;
+  Expression* iterable_;
+  FeedbackSlot iterator_property_feedback_slot_;
+  FeedbackSlot iterator_call_feedback_slot_;
+  FeedbackSlot async_iterator_property_feedback_slot_;
+  FeedbackSlot async_iterator_call_feedback_slot_;
+};
 
 // ----------------------------------------------------------------------------
 // Basic visitor
@@ -3170,6 +3202,11 @@
     return NULL;
   }
 
+  ForOfStatement* NewForOfStatement(ZoneList<const AstRawString*>* labels,
+                                    int pos) {
+    return new (zone_) ForOfStatement(labels, pos);
+  }
+
   ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) {
     return new (zone_) ExpressionStatement(expression, pos);
   }
@@ -3183,7 +3220,13 @@
   }
 
   ReturnStatement* NewReturnStatement(Expression* expression, int pos) {
-    return new (zone_) ReturnStatement(expression, pos);
+    return new (zone_)
+        ReturnStatement(expression, ReturnStatement::kNormal, pos);
+  }
+
+  ReturnStatement* NewAsyncReturnStatement(Expression* expression, int pos) {
+    return new (zone_)
+        ReturnStatement(expression, ReturnStatement::kAsyncReturn, pos);
   }
 
   WithStatement* NewWithStatement(Scope* scope,
@@ -3217,15 +3260,6 @@
         try_block, scope, variable, catch_block, HandlerTable::UNCAUGHT, pos);
   }
 
-  TryCatchStatement* NewTryCatchStatementForPromiseReject(Block* try_block,
-                                                          Scope* scope,
-                                                          Variable* variable,
-                                                          Block* catch_block,
-                                                          int pos) {
-    return new (zone_) TryCatchStatement(
-        try_block, scope, variable, catch_block, HandlerTable::PROMISE, pos);
-  }
-
   TryCatchStatement* NewTryCatchStatementForDesugaring(Block* try_block,
                                                        Scope* scope,
                                                        Variable* variable,
@@ -3258,9 +3292,9 @@
     return new (zone_) EmptyStatement(pos);
   }
 
-  SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(Scope* scope) {
-    return new (zone_) SloppyBlockFunctionStatement(
-        NewEmptyStatement(kNoSourcePosition), scope);
+  SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement() {
+    return new (zone_)
+        SloppyBlockFunctionStatement(NewEmptyStatement(kNoSourcePosition));
   }
 
   CaseClause* NewCaseClause(
@@ -3273,8 +3307,8 @@
   }
 
   // A JavaScript symbol (ECMA-262 edition 6).
-  Literal* NewSymbolLiteral(const char* name, int pos) {
-    return new (zone_) Literal(ast_value_factory_->NewSymbol(name), pos);
+  Literal* NewSymbolLiteral(AstSymbol symbol, int pos) {
+    return new (zone_) Literal(ast_value_factory_->NewSymbol(symbol), pos);
   }
 
   Literal* NewNumberLiteral(double number, int pos, bool with_dot = false) {
@@ -3303,10 +3337,10 @@
   }
 
   ObjectLiteral* NewObjectLiteral(
-      ZoneList<ObjectLiteral::Property*>* properties, int literal_index,
-      uint32_t boilerplate_properties, int pos) {
-    return new (zone_)
-        ObjectLiteral(properties, literal_index, boilerplate_properties, pos);
+      ZoneList<ObjectLiteral::Property*>* properties,
+      uint32_t boilerplate_properties, int pos, bool has_rest_property) {
+    return new (zone_) ObjectLiteral(properties, boilerplate_properties, pos,
+                                     has_rest_property);
   }
 
   ObjectLiteral::Property* NewObjectLiteralProperty(
@@ -3324,21 +3358,18 @@
   }
 
   RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern, int flags,
-                                  int literal_index, int pos) {
-    return new (zone_) RegExpLiteral(pattern, flags, literal_index, pos);
+                                  int pos) {
+    return new (zone_) RegExpLiteral(pattern, flags, pos);
   }
 
   ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
-                                int literal_index,
                                 int pos) {
-    return new (zone_) ArrayLiteral(values, -1, literal_index, pos);
+    return new (zone_) ArrayLiteral(values, -1, pos);
   }
 
   ArrayLiteral* NewArrayLiteral(ZoneList<Expression*>* values,
-                                int first_spread_index, int literal_index,
-                                int pos) {
-    return new (zone_)
-        ArrayLiteral(values, first_spread_index, literal_index, pos);
+                                int first_spread_index, int pos) {
+    return new (zone_) ArrayLiteral(values, first_spread_index, pos);
   }
 
   VariableProxy* NewVariableProxy(Variable* var,
@@ -3437,9 +3468,13 @@
                             Expression* value,
                             int pos) {
     DCHECK(Token::IsAssignmentOp(op));
+
+    if (op != Token::INIT && target->IsVariableProxy()) {
+      target->AsVariableProxy()->set_is_assigned();
+    }
+
     Assignment* assign = new (zone_) Assignment(op, target, value, pos);
     if (assign->is_compound()) {
-      DCHECK(Token::IsAssignmentOp(op));
       assign->binary_operation_ =
           NewBinaryOperation(assign->binary_op(), target, value, pos + 1);
     }
@@ -3458,32 +3493,33 @@
 
   FunctionLiteral* NewFunctionLiteral(
       const AstRawString* name, DeclarationScope* scope,
-      ZoneList<Statement*>* body, int materialized_literal_count,
-      int expected_property_count, int parameter_count, int function_length,
+      ZoneList<Statement*>* body, int expected_property_count,
+      int parameter_count, int function_length,
       FunctionLiteral::ParameterFlag has_duplicate_parameters,
       FunctionLiteral::FunctionType function_type,
       FunctionLiteral::EagerCompileHint eager_compile_hint, int position,
-      bool has_braces) {
+      bool has_braces, int function_literal_id) {
     return new (zone_) FunctionLiteral(
-        zone_, name, ast_value_factory_, scope, body,
-        materialized_literal_count, expected_property_count, parameter_count,
-        function_length, function_type, has_duplicate_parameters,
-        eager_compile_hint, position, true, has_braces);
+        zone_, name, ast_value_factory_, scope, body, expected_property_count,
+        parameter_count, function_length, function_type,
+        has_duplicate_parameters, eager_compile_hint, position, has_braces,
+        function_literal_id);
   }
 
   // Creates a FunctionLiteral representing a top-level script, the
   // result of an eval (top-level or otherwise), or the result of calling
   // the Function constructor.
-  FunctionLiteral* NewScriptOrEvalFunctionLiteral(
-      DeclarationScope* scope, ZoneList<Statement*>* body,
-      int materialized_literal_count, int expected_property_count,
-      int parameter_count) {
+  FunctionLiteral* NewScriptOrEvalFunctionLiteral(DeclarationScope* scope,
+                                                  ZoneList<Statement*>* body,
+                                                  int expected_property_count,
+                                                  int parameter_count) {
     return new (zone_) FunctionLiteral(
         zone_, ast_value_factory_->empty_string(), ast_value_factory_, scope,
-        body, materialized_literal_count, expected_property_count,
-        parameter_count, parameter_count, FunctionLiteral::kAnonymousExpression,
+        body, expected_property_count, parameter_count, parameter_count,
+        FunctionLiteral::kAnonymousExpression,
         FunctionLiteral::kNoDuplicateParameters,
-        FunctionLiteral::kShouldLazyCompile, 0, false, true);
+        FunctionLiteral::kShouldLazyCompile, 0, true,
+        FunctionLiteral::kIdTypeTopLevel);
   }
 
   ClassLiteral::Property* NewClassLiteralProperty(
@@ -3496,9 +3532,12 @@
   ClassLiteral* NewClassLiteral(VariableProxy* proxy, Expression* extends,
                                 FunctionLiteral* constructor,
                                 ZoneList<ClassLiteral::Property*>* properties,
-                                int start_position, int end_position) {
-    return new (zone_) ClassLiteral(proxy, extends, constructor, properties,
-                                    start_position, end_position);
+                                int start_position, int end_position,
+                                bool has_name_static_property,
+                                bool has_static_computed_names) {
+    return new (zone_) ClassLiteral(
+        proxy, extends, constructor, properties, start_position, end_position,
+        has_name_static_property, has_static_computed_names);
   }
 
   NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name,
@@ -3534,6 +3573,11 @@
     return new (zone_) EmptyParentheses(pos);
   }
 
+  GetIterator* NewGetIterator(Expression* iterable, IteratorType hint,
+                              int pos) {
+    return new (zone_) GetIterator(iterable, hint, pos);
+  }
+
   Zone* zone() const { return zone_; }
   void set_zone(Zone* zone) { zone_ = zone; }
 
diff --git a/src/ast/compile-time-value.cc b/src/ast/compile-time-value.cc
index eda536b..27dd29f 100644
--- a/src/ast/compile-time-value.cc
+++ b/src/ast/compile-time-value.cc
@@ -48,8 +48,8 @@
   return static_cast<LiteralType>(literal_type->value());
 }
 
-Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
-  return Handle<FixedArray>(FixedArray::cast(value->get(kElementsSlot)));
+Handle<HeapObject> CompileTimeValue::GetElements(Handle<FixedArray> value) {
+  return Handle<HeapObject>(HeapObject::cast(value->get(kElementsSlot)));
 }
 
 }  // namespace internal
diff --git a/src/ast/compile-time-value.h b/src/ast/compile-time-value.h
index 27351b7..d61443e 100644
--- a/src/ast/compile-time-value.h
+++ b/src/ast/compile-time-value.h
@@ -31,8 +31,8 @@
   // Get the type of a compile time value returned by GetValue().
   static LiteralType GetLiteralType(Handle<FixedArray> value);
 
-  // Get the elements array of a compile time value returned by GetValue().
-  static Handle<FixedArray> GetElements(Handle<FixedArray> value);
+  // Get the elements of a compile time value returned by GetValue().
+  static Handle<HeapObject> GetElements(Handle<FixedArray> value);
 
  private:
   static const int kLiteralTypeSlot = 0;
diff --git a/src/ast/context-slot-cache.cc b/src/ast/context-slot-cache.cc
index b1387e1..4548218 100644
--- a/src/ast/context-slot-cache.cc
+++ b/src/ast/context-slot-cache.cc
@@ -12,9 +12,9 @@
 // (disallowed) include: src/factory.h -> src/objects-inl.h
 #include "src/objects-inl.h"
 // FIXME(mstarzinger, marja): This is weird, but required because of the missing
-// (disallowed) include: src/type-feedback-vector.h ->
-// src/type-feedback-vector-inl.h
-#include "src/type-feedback-vector-inl.h"
+// (disallowed) include: src/feedback-vector.h ->
+// src/feedback-vector-inl.h
+#include "src/feedback-vector-inl.h"
 
 namespace v8 {
 namespace internal {
diff --git a/src/ast/modules.cc b/src/ast/modules.cc
index 339d64c..9d3a235 100644
--- a/src/ast/modules.cc
+++ b/src/ast/modules.cc
@@ -5,6 +5,9 @@
 #include "src/ast/modules.h"
 #include "src/ast/ast-value-factory.h"
 #include "src/ast/scopes.h"
+#include "src/objects-inl.h"
+#include "src/objects/module-info.h"
+#include "src/pending-compilation-error-handler.h"
 
 namespace v8 {
 namespace internal {
diff --git a/src/ast/modules.h b/src/ast/modules.h
index 94550fb..ce8aba8 100644
--- a/src/ast/modules.h
+++ b/src/ast/modules.h
@@ -6,7 +6,6 @@
 #define V8_AST_MODULES_H_
 
 #include "src/parsing/scanner.h"  // Only for Scanner::Location.
-#include "src/pending-compilation-error-handler.h"
 #include "src/zone/zone-containers.h"
 
 namespace v8 {
@@ -16,6 +15,7 @@
 class AstRawString;
 class ModuleInfo;
 class ModuleInfoEntry;
+class PendingCompilationErrorHandler;
 
 class ModuleDescriptor : public ZoneObject {
  public:
diff --git a/src/ast/prettyprinter.cc b/src/ast/prettyprinter.cc
index a3fc50a..725a8a7 100644
--- a/src/ast/prettyprinter.cc
+++ b/src/ast/prettyprinter.cc
@@ -10,18 +10,19 @@
 #include "src/ast/scopes.h"
 #include "src/base/platform/platform.h"
 #include "src/globals.h"
+#include "src/objects-inl.h"
 
 namespace v8 {
 namespace internal {
 
-CallPrinter::CallPrinter(Isolate* isolate, bool is_builtin)
+CallPrinter::CallPrinter(Isolate* isolate, bool is_user_js)
     : builder_(isolate) {
   isolate_ = isolate;
   position_ = 0;
   num_prints_ = 0;
   found_ = false;
   done_ = false;
-  is_builtin_ = is_builtin;
+  is_user_js_ = is_user_js;
   InitializeAstVisitor(isolate);
 }
 
@@ -239,11 +240,11 @@
 
 
 void CallPrinter::VisitVariableProxy(VariableProxy* node) {
-  if (is_builtin_) {
-    // Variable names of builtins are meaningless due to minification.
-    Print("(var)");
-  } else {
+  if (is_user_js_) {
     PrintLiteral(node->name(), false);
+  } else {
+    // Variable names of non-user code are meaningless due to minification.
+    Print("(var)");
   }
 }
 
@@ -279,9 +280,9 @@
 void CallPrinter::VisitCall(Call* node) {
   bool was_found = !found_ && node->position() == position_;
   if (was_found) {
-    // Bail out if the error is caused by a direct call to a variable in builtin
-    // code. The variable name is meaningless due to minification.
-    if (is_builtin_ && node->expression()->IsVariableProxy()) {
+    // Bail out if the error is caused by a direct call to a variable in
+    // non-user JS code. The variable name is meaningless due to minification.
+    if (!is_user_js_ && node->expression()->IsVariableProxy()) {
       done_ = true;
       return;
     }
@@ -297,9 +298,9 @@
 void CallPrinter::VisitCallNew(CallNew* node) {
   bool was_found = !found_ && node->position() == position_;
   if (was_found) {
-    // Bail out if the error is caused by a direct call to a variable in builtin
-    // code. The variable name is meaningless due to minification.
-    if (is_builtin_ && node->expression()->IsVariableProxy()) {
+    // Bail out if the error is caused by a direct call to a variable in
+    // non-user JS code. The variable name is meaningless due to minification.
+    if (!is_user_js_ && node->expression()->IsVariableProxy()) {
       done_ = true;
       return;
     }
@@ -370,6 +371,11 @@
   UNREACHABLE();
 }
 
+void CallPrinter::VisitGetIterator(GetIterator* node) {
+  Print("GetIterator(");
+  Find(node->iterable(), true);
+  Print(")");
+}
 
 void CallPrinter::VisitThisFunction(ThisFunction* node) {}
 
@@ -434,9 +440,9 @@
 
 #ifdef DEBUG
 
-// A helper for ast nodes that use FeedbackVectorSlots.
+// A helper for ast nodes that use FeedbackSlots.
 static int FormatSlotNode(Vector<char>* buf, Expression* node,
-                          const char* node_name, FeedbackVectorSlot slot) {
+                          const char* node_name, FeedbackSlot slot) {
   int pos = SNPrintF(*buf, "%s", node_name);
   if (!slot.IsInvalid()) {
     pos += SNPrintF(*buf + pos, " Slot(%d)", slot.ToInt());
@@ -874,15 +880,16 @@
     case HandlerTable::CAUGHT:
       prediction = "CAUGHT";
       break;
-    case HandlerTable::PROMISE:
-      prediction = "PROMISE";
-      break;
     case HandlerTable::DESUGARING:
       prediction = "DESUGARING";
       break;
     case HandlerTable::ASYNC_AWAIT:
       prediction = "ASYNC_AWAIT";
       break;
+    case HandlerTable::PROMISE:
+      // Catch prediction resulting in promise rejections aren't
+      // parsed by the parser.
+      UNREACHABLE();
   }
   Print(" %s\n", prediction);
 }
@@ -971,7 +978,7 @@
 void AstPrinter::VisitRegExpLiteral(RegExpLiteral* node) {
   IndentedScope indent(this, "REGEXP LITERAL", node->position());
   EmbeddedVector<char, 128> buf;
-  SNPrintF(buf, "literal_index = %d\n", node->literal_index());
+  SNPrintF(buf, "literal_slot = %d\n", node->literal_slot().ToInt());
   PrintIndented(buf.start());
   PrintLiteralIndented("PATTERN", node->pattern(), false);
   int i = 0;
@@ -990,7 +997,7 @@
 void AstPrinter::VisitObjectLiteral(ObjectLiteral* node) {
   IndentedScope indent(this, "OBJ LITERAL", node->position());
   EmbeddedVector<char, 128> buf;
-  SNPrintF(buf, "literal_index = %d\n", node->literal_index());
+  SNPrintF(buf, "literal_slot = %d\n", node->literal_slot().ToInt());
   PrintIndented(buf.start());
   PrintObjectProperties(node->properties());
 }
@@ -1019,6 +1026,9 @@
       case ObjectLiteral::Property::SETTER:
         prop_kind = "SETTER";
         break;
+      case ObjectLiteral::Property::SPREAD:
+        prop_kind = "SPREAD";
+        break;
     }
     EmbeddedVector<char, 128> buf;
     SNPrintF(buf, "PROPERTY - %s", prop_kind);
@@ -1033,7 +1043,7 @@
   IndentedScope indent(this, "ARRAY LITERAL", node->position());
 
   EmbeddedVector<char, 128> buf;
-  SNPrintF(buf, "literal_index = %d\n", node->literal_index());
+  SNPrintF(buf, "literal_slot = %d\n", node->literal_slot().ToInt());
   PrintIndented(buf.start());
   if (node->values()->length() > 0) {
     IndentedScope indent(this, "VALUES", node->position());
@@ -1136,7 +1146,14 @@
 
 void AstPrinter::VisitCallRuntime(CallRuntime* node) {
   EmbeddedVector<char, 128> buf;
-  SNPrintF(buf, "CALL RUNTIME %s", node->debug_name());
+  if (node->is_jsruntime()) {
+    SNPrintF(
+        buf, "CALL RUNTIME %s code = %p", node->debug_name(),
+        static_cast<void*>(isolate_->context()->get(node->context_index())));
+  } else {
+    SNPrintF(buf, "CALL RUNTIME %s", node->debug_name());
+  }
+
   IndentedScope indent(this, buf.start(), node->position());
   PrintArguments(node->arguments());
 }
@@ -1181,6 +1198,10 @@
   IndentedScope indent(this, "()", node->position());
 }
 
+void AstPrinter::VisitGetIterator(GetIterator* node) {
+  IndentedScope indent(this, "GET-ITERATOR", node->position());
+  Visit(node->iterable());
+}
 
 void AstPrinter::VisitThisFunction(ThisFunction* node) {
   IndentedScope indent(this, "THIS-FUNCTION", node->position());
diff --git a/src/ast/prettyprinter.h b/src/ast/prettyprinter.h
index b56c834..fdc079c 100644
--- a/src/ast/prettyprinter.h
+++ b/src/ast/prettyprinter.h
@@ -15,7 +15,7 @@
 
 class CallPrinter final : public AstVisitor<CallPrinter> {
  public:
-  explicit CallPrinter(Isolate* isolate, bool is_builtin);
+  explicit CallPrinter(Isolate* isolate, bool is_user_js);
 
   // The following routine prints the node with position |position| into a
   // string.
@@ -38,7 +38,7 @@
   int position_;  // position of ast node to print
   bool found_;
   bool done_;
-  bool is_builtin_;
+  bool is_user_js_;
 
   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
 
diff --git a/src/ast/scopeinfo.cc b/src/ast/scopeinfo.cc
deleted file mode 100644
index 3a3ea03..0000000
--- a/src/ast/scopeinfo.cc
+++ /dev/null
@@ -1,975 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdlib.h>
-
-#include "src/ast/context-slot-cache.h"
-#include "src/ast/scopes.h"
-#include "src/ast/variables.h"
-#include "src/bootstrapper.h"
-
-namespace v8 {
-namespace internal {
-
-// An entry in ModuleVariableEntries consists of several slots:
-enum ModuleVariableEntryOffset {
-  kModuleVariableNameOffset,
-  kModuleVariableIndexOffset,
-  kModuleVariablePropertiesOffset,
-  kModuleVariableEntryLength  // Sentinel value.
-};
-
-#ifdef DEBUG
-bool ScopeInfo::Equals(ScopeInfo* other) const {
-  if (length() != other->length()) return false;
-  for (int index = 0; index < length(); ++index) {
-    Object* entry = get(index);
-    Object* other_entry = other->get(index);
-    if (entry->IsSmi()) {
-      if (entry != other_entry) return false;
-    } else {
-      if (HeapObject::cast(entry)->map()->instance_type() !=
-          HeapObject::cast(other_entry)->map()->instance_type()) {
-        return false;
-      }
-      if (entry->IsString()) {
-        if (!String::cast(entry)->Equals(String::cast(other_entry))) {
-          return false;
-        }
-      } else if (entry->IsScopeInfo()) {
-        if (!ScopeInfo::cast(entry)->Equals(ScopeInfo::cast(other_entry))) {
-          return false;
-        }
-      } else if (entry->IsModuleInfo()) {
-        if (!ModuleInfo::cast(entry)->Equals(ModuleInfo::cast(other_entry))) {
-          return false;
-        }
-      } else {
-        UNREACHABLE();
-        return false;
-      }
-    }
-  }
-  return true;
-}
-#endif
-
-Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
-                                    MaybeHandle<ScopeInfo> outer_scope) {
-  // Collect variables.
-  int stack_local_count = 0;
-  int context_local_count = 0;
-  int module_vars_count = 0;
-  // Stack allocated block scope variables are allocated in the parent
-  // declaration scope, but are recorded in the block scope's scope info. First
-  // slot index indicates at which offset a particular scope starts in the
-  // parent declaration scope.
-  int first_slot_index = 0;
-  for (Variable* var : *scope->locals()) {
-    switch (var->location()) {
-      case VariableLocation::LOCAL:
-        if (stack_local_count == 0) first_slot_index = var->index();
-        stack_local_count++;
-        break;
-      case VariableLocation::CONTEXT:
-        context_local_count++;
-        break;
-      case VariableLocation::MODULE:
-        module_vars_count++;
-        break;
-      default:
-        break;
-    }
-  }
-  DCHECK(module_vars_count == 0 || scope->is_module_scope());
-
-  // Make sure we allocate the correct amount.
-  DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
-
-  // Determine use and location of the "this" binding if it is present.
-  VariableAllocationInfo receiver_info;
-  if (scope->is_declaration_scope() &&
-      scope->AsDeclarationScope()->has_this_declaration()) {
-    Variable* var = scope->AsDeclarationScope()->receiver();
-    if (!var->is_used()) {
-      receiver_info = UNUSED;
-    } else if (var->IsContextSlot()) {
-      receiver_info = CONTEXT;
-    } else {
-      DCHECK(var->IsParameter());
-      receiver_info = STACK;
-    }
-  } else {
-    receiver_info = NONE;
-  }
-
-  bool has_new_target =
-      scope->is_declaration_scope() &&
-      scope->AsDeclarationScope()->new_target_var() != nullptr;
-
-  // Determine use and location of the function variable if it is present.
-  VariableAllocationInfo function_name_info;
-  if (scope->is_function_scope() &&
-      scope->AsDeclarationScope()->function_var() != nullptr) {
-    Variable* var = scope->AsDeclarationScope()->function_var();
-    if (!var->is_used()) {
-      function_name_info = UNUSED;
-    } else if (var->IsContextSlot()) {
-      function_name_info = CONTEXT;
-    } else {
-      DCHECK(var->IsStackLocal());
-      function_name_info = STACK;
-    }
-  } else {
-    function_name_info = NONE;
-  }
-
-  const bool has_function_name = function_name_info != NONE;
-  const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT;
-  const int parameter_count = scope->num_parameters();
-  const bool has_outer_scope_info = !outer_scope.is_null();
-  const int length = kVariablePartIndex + parameter_count +
-                     (1 + stack_local_count) + 2 * context_local_count +
-                     (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) +
-                     (has_outer_scope_info ? 1 : 0) +
-                     (scope->is_module_scope()
-                          ? 2 + kModuleVariableEntryLength * module_vars_count
-                          : 0);
-
-  Factory* factory = isolate->factory();
-  Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
-
-  bool has_simple_parameters = false;
-  bool asm_module = false;
-  bool asm_function = false;
-  FunctionKind function_kind = kNormalFunction;
-  if (scope->is_function_scope()) {
-    DeclarationScope* function_scope = scope->AsDeclarationScope();
-    has_simple_parameters = function_scope->has_simple_parameters();
-    asm_module = function_scope->asm_module();
-    asm_function = function_scope->asm_function();
-    function_kind = function_scope->function_kind();
-  }
-
-  // Encode the flags.
-  int flags =
-      ScopeTypeField::encode(scope->scope_type()) |
-      CallsEvalField::encode(scope->calls_eval()) |
-      LanguageModeField::encode(scope->language_mode()) |
-      DeclarationScopeField::encode(scope->is_declaration_scope()) |
-      ReceiverVariableField::encode(receiver_info) |
-      HasNewTargetField::encode(has_new_target) |
-      FunctionVariableField::encode(function_name_info) |
-      AsmModuleField::encode(asm_module) |
-      AsmFunctionField::encode(asm_function) |
-      HasSimpleParametersField::encode(has_simple_parameters) |
-      FunctionKindField::encode(function_kind) |
-      HasOuterScopeInfoField::encode(has_outer_scope_info) |
-      IsDebugEvaluateScopeField::encode(scope->is_debug_evaluate_scope());
-  scope_info->SetFlags(flags);
-
-  scope_info->SetParameterCount(parameter_count);
-  scope_info->SetStackLocalCount(stack_local_count);
-  scope_info->SetContextLocalCount(context_local_count);
-
-  int index = kVariablePartIndex;
-  // Add parameters.
-  DCHECK_EQ(index, scope_info->ParameterNamesIndex());
-  if (scope->is_declaration_scope()) {
-    for (int i = 0; i < parameter_count; ++i) {
-      scope_info->set(index++,
-                      *scope->AsDeclarationScope()->parameter(i)->name());
-    }
-  }
-
-  // Add stack locals' names, context locals' names and info, module variables'
-  // names and info. We are assuming that the stack locals' slots are allocated
-  // in increasing order, so we can simply add them to the ScopeInfo object.
-  // Context locals are added using their index.
-  DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex());
-  scope_info->set(index++, Smi::FromInt(first_slot_index));
-  DCHECK_EQ(index, scope_info->StackLocalNamesIndex());
-
-  int stack_local_base = index;
-  int context_local_base = stack_local_base + stack_local_count;
-  int context_local_info_base = context_local_base + context_local_count;
-  int module_var_entry = scope_info->ModuleVariablesIndex();
-
-  for (Variable* var : *scope->locals()) {
-    switch (var->location()) {
-      case VariableLocation::LOCAL: {
-        int local_index = var->index() - first_slot_index;
-        DCHECK_LE(0, local_index);
-        DCHECK_LT(local_index, stack_local_count);
-        scope_info->set(stack_local_base + local_index, *var->name());
-        break;
-      }
-      case VariableLocation::CONTEXT: {
-        // Due to duplicate parameters, context locals aren't guaranteed to come
-        // in order.
-        int local_index = var->index() - Context::MIN_CONTEXT_SLOTS;
-        DCHECK_LE(0, local_index);
-        DCHECK_LT(local_index, context_local_count);
-        uint32_t info = VariableModeField::encode(var->mode()) |
-                        InitFlagField::encode(var->initialization_flag()) |
-                        MaybeAssignedFlagField::encode(var->maybe_assigned());
-        scope_info->set(context_local_base + local_index, *var->name());
-        scope_info->set(context_local_info_base + local_index,
-                        Smi::FromInt(info));
-        break;
-      }
-      case VariableLocation::MODULE: {
-        scope_info->set(module_var_entry + kModuleVariableNameOffset,
-                        *var->name());
-        scope_info->set(module_var_entry + kModuleVariableIndexOffset,
-                        Smi::FromInt(var->index()));
-        uint32_t properties =
-            VariableModeField::encode(var->mode()) |
-            InitFlagField::encode(var->initialization_flag()) |
-            MaybeAssignedFlagField::encode(var->maybe_assigned());
-        scope_info->set(module_var_entry + kModuleVariablePropertiesOffset,
-                        Smi::FromInt(properties));
-        module_var_entry += kModuleVariableEntryLength;
-        break;
-      }
-      default:
-        break;
-    }
-  }
-
-  index += stack_local_count + 2 * context_local_count;
-
-  // If the receiver is allocated, add its index.
-  DCHECK_EQ(index, scope_info->ReceiverInfoIndex());
-  if (has_receiver) {
-    int var_index = scope->AsDeclarationScope()->receiver()->index();
-    scope_info->set(index++, Smi::FromInt(var_index));
-    // ?? DCHECK(receiver_info != CONTEXT || var_index ==
-    // scope_info->ContextLength() - 1);
-  }
-
-  // If present, add the function variable name and its index.
-  DCHECK_EQ(index, scope_info->FunctionNameInfoIndex());
-  if (has_function_name) {
-    int var_index = scope->AsDeclarationScope()->function_var()->index();
-    scope_info->set(index++,
-                    *scope->AsDeclarationScope()->function_var()->name());
-    scope_info->set(index++, Smi::FromInt(var_index));
-    DCHECK(function_name_info != CONTEXT ||
-           var_index == scope_info->ContextLength() - 1);
-  }
-
-  // If present, add the outer scope info.
-  DCHECK(index == scope_info->OuterScopeInfoIndex());
-  if (has_outer_scope_info) {
-    scope_info->set(index++, *outer_scope.ToHandleChecked());
-  }
-
-  // Module-specific information (only for module scopes).
-  if (scope->is_module_scope()) {
-    Handle<ModuleInfo> module_info =
-        ModuleInfo::New(isolate, zone, scope->AsModuleScope()->module());
-    DCHECK_EQ(index, scope_info->ModuleInfoIndex());
-    scope_info->set(index++, *module_info);
-    DCHECK_EQ(index, scope_info->ModuleVariableCountIndex());
-    scope_info->set(index++, Smi::FromInt(module_vars_count));
-    DCHECK_EQ(index, scope_info->ModuleVariablesIndex());
-    // The variable entries themselves have already been written above.
-    index += kModuleVariableEntryLength * module_vars_count;
-  }
-
-  DCHECK_EQ(index, scope_info->length());
-  DCHECK_EQ(scope->num_parameters(), scope_info->ParameterCount());
-  DCHECK_EQ(scope->num_heap_slots(), scope_info->ContextLength());
-  return scope_info;
-}
-
-Handle<ScopeInfo> ScopeInfo::CreateForWithScope(
-    Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope) {
-  const bool has_outer_scope_info = !outer_scope.is_null();
-  const int length = kVariablePartIndex + 1 + (has_outer_scope_info ? 1 : 0);
-
-  Factory* factory = isolate->factory();
-  Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
-
-  // Encode the flags.
-  int flags =
-      ScopeTypeField::encode(WITH_SCOPE) | CallsEvalField::encode(false) |
-      LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(false) |
-      ReceiverVariableField::encode(NONE) | HasNewTargetField::encode(false) |
-      FunctionVariableField::encode(NONE) | AsmModuleField::encode(false) |
-      AsmFunctionField::encode(false) | HasSimpleParametersField::encode(true) |
-      FunctionKindField::encode(kNormalFunction) |
-      HasOuterScopeInfoField::encode(has_outer_scope_info) |
-      IsDebugEvaluateScopeField::encode(false);
-  scope_info->SetFlags(flags);
-
-  scope_info->SetParameterCount(0);
-  scope_info->SetStackLocalCount(0);
-  scope_info->SetContextLocalCount(0);
-
-  int index = kVariablePartIndex;
-  DCHECK_EQ(index, scope_info->ParameterNamesIndex());
-  DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex());
-  scope_info->set(index++, Smi::kZero);
-  DCHECK_EQ(index, scope_info->StackLocalNamesIndex());
-  DCHECK_EQ(index, scope_info->ReceiverInfoIndex());
-  DCHECK_EQ(index, scope_info->FunctionNameInfoIndex());
-  DCHECK(index == scope_info->OuterScopeInfoIndex());
-  if (has_outer_scope_info) {
-    scope_info->set(index++, *outer_scope.ToHandleChecked());
-  }
-  DCHECK_EQ(index, scope_info->length());
-  DCHECK_EQ(0, scope_info->ParameterCount());
-  DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, scope_info->ContextLength());
-  return scope_info;
-}
-
-Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
-  DCHECK(isolate->bootstrapper()->IsActive());
-
-  const int stack_local_count = 0;
-  const int context_local_count = 1;
-  const bool has_simple_parameters = true;
-  const VariableAllocationInfo receiver_info = CONTEXT;
-  const VariableAllocationInfo function_name_info = NONE;
-  const bool has_function_name = false;
-  const bool has_receiver = true;
-  const bool has_outer_scope_info = false;
-  const int parameter_count = 0;
-  const int length = kVariablePartIndex + parameter_count +
-                     (1 + stack_local_count) + 2 * context_local_count +
-                     (has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) +
-                     (has_outer_scope_info ? 1 : 0);
-
-  Factory* factory = isolate->factory();
-  Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
-
-  // Encode the flags.
-  int flags =
-      ScopeTypeField::encode(SCRIPT_SCOPE) | CallsEvalField::encode(false) |
-      LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(true) |
-      ReceiverVariableField::encode(receiver_info) |
-      FunctionVariableField::encode(function_name_info) |
-      AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
-      HasSimpleParametersField::encode(has_simple_parameters) |
-      FunctionKindField::encode(FunctionKind::kNormalFunction) |
-      HasOuterScopeInfoField::encode(has_outer_scope_info) |
-      IsDebugEvaluateScopeField::encode(false);
-  scope_info->SetFlags(flags);
-  scope_info->SetParameterCount(parameter_count);
-  scope_info->SetStackLocalCount(stack_local_count);
-  scope_info->SetContextLocalCount(context_local_count);
-
-  int index = kVariablePartIndex;
-  const int first_slot_index = 0;
-  DCHECK_EQ(index, scope_info->StackLocalFirstSlotIndex());
-  scope_info->set(index++, Smi::FromInt(first_slot_index));
-  DCHECK_EQ(index, scope_info->StackLocalNamesIndex());
-
-  // Here we add info for context-allocated "this".
-  DCHECK_EQ(index, scope_info->ContextLocalNamesIndex());
-  scope_info->set(index++, isolate->heap()->this_string());
-  DCHECK_EQ(index, scope_info->ContextLocalInfosIndex());
-  const uint32_t value = VariableModeField::encode(CONST) |
-                         InitFlagField::encode(kCreatedInitialized) |
-                         MaybeAssignedFlagField::encode(kNotAssigned);
-  scope_info->set(index++, Smi::FromInt(value));
-
-  // And here we record that this scopeinfo binds a receiver.
-  DCHECK_EQ(index, scope_info->ReceiverInfoIndex());
-  const int receiver_index = Context::MIN_CONTEXT_SLOTS + 0;
-  scope_info->set(index++, Smi::FromInt(receiver_index));
-
-  DCHECK_EQ(index, scope_info->FunctionNameInfoIndex());
-  DCHECK_EQ(index, scope_info->OuterScopeInfoIndex());
-  DCHECK_EQ(index, scope_info->length());
-  DCHECK_EQ(scope_info->ParameterCount(), 0);
-  DCHECK_EQ(scope_info->ContextLength(), Context::MIN_CONTEXT_SLOTS + 1);
-
-  return scope_info;
-}
-
-
-ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
-  return isolate->heap()->empty_scope_info();
-}
-
-
-ScopeType ScopeInfo::scope_type() {
-  DCHECK_LT(0, length());
-  return ScopeTypeField::decode(Flags());
-}
-
-
-bool ScopeInfo::CallsEval() {
-  return length() > 0 && CallsEvalField::decode(Flags());
-}
-
-
-LanguageMode ScopeInfo::language_mode() {
-  return length() > 0 ? LanguageModeField::decode(Flags()) : SLOPPY;
-}
-
-
-bool ScopeInfo::is_declaration_scope() {
-  return DeclarationScopeField::decode(Flags());
-}
-
-
-int ScopeInfo::LocalCount() {
-  return StackLocalCount() + ContextLocalCount();
-}
-
-
-int ScopeInfo::StackSlotCount() {
-  if (length() > 0) {
-    bool function_name_stack_slot =
-        FunctionVariableField::decode(Flags()) == STACK;
-    return StackLocalCount() + (function_name_stack_slot ? 1 : 0);
-  }
-  return 0;
-}
-
-
-int ScopeInfo::ContextLength() {
-  if (length() > 0) {
-    int context_locals = ContextLocalCount();
-    bool function_name_context_slot =
-        FunctionVariableField::decode(Flags()) == CONTEXT;
-    bool has_context = context_locals > 0 || function_name_context_slot ||
-                       scope_type() == WITH_SCOPE ||
-                       (scope_type() == BLOCK_SCOPE && CallsSloppyEval() &&
-                        is_declaration_scope()) ||
-                       (scope_type() == FUNCTION_SCOPE && CallsSloppyEval()) ||
-                       scope_type() == MODULE_SCOPE;
-
-    if (has_context) {
-      return Context::MIN_CONTEXT_SLOTS + context_locals +
-             (function_name_context_slot ? 1 : 0);
-    }
-  }
-  return 0;
-}
-
-
-bool ScopeInfo::HasReceiver() {
-  if (length() > 0) {
-    return NONE != ReceiverVariableField::decode(Flags());
-  } else {
-    return false;
-  }
-}
-
-
-bool ScopeInfo::HasAllocatedReceiver() {
-  if (length() > 0) {
-    VariableAllocationInfo allocation = ReceiverVariableField::decode(Flags());
-    return allocation == STACK || allocation == CONTEXT;
-  } else {
-    return false;
-  }
-}
-
-
-bool ScopeInfo::HasNewTarget() { return HasNewTargetField::decode(Flags()); }
-
-
-bool ScopeInfo::HasFunctionName() {
-  if (length() > 0) {
-    return NONE != FunctionVariableField::decode(Flags());
-  } else {
-    return false;
-  }
-}
-
-bool ScopeInfo::HasOuterScopeInfo() {
-  if (length() > 0) {
-    return HasOuterScopeInfoField::decode(Flags());
-  } else {
-    return false;
-  }
-}
-
-bool ScopeInfo::IsDebugEvaluateScope() {
-  if (length() > 0) {
-    return IsDebugEvaluateScopeField::decode(Flags());
-  } else {
-    return false;
-  }
-}
-
-void ScopeInfo::SetIsDebugEvaluateScope() {
-  if (length() > 0) {
-    DCHECK_EQ(scope_type(), WITH_SCOPE);
-    SetFlags(Flags() | IsDebugEvaluateScopeField::encode(true));
-  } else {
-    UNREACHABLE();
-  }
-}
-
-bool ScopeInfo::HasHeapAllocatedLocals() {
-  if (length() > 0) {
-    return ContextLocalCount() > 0;
-  } else {
-    return false;
-  }
-}
-
-
-bool ScopeInfo::HasContext() {
-  return ContextLength() > 0;
-}
-
-
-String* ScopeInfo::FunctionName() {
-  DCHECK(HasFunctionName());
-  return String::cast(get(FunctionNameInfoIndex()));
-}
-
-ScopeInfo* ScopeInfo::OuterScopeInfo() {
-  DCHECK(HasOuterScopeInfo());
-  return ScopeInfo::cast(get(OuterScopeInfoIndex()));
-}
-
-ModuleInfo* ScopeInfo::ModuleDescriptorInfo() {
-  DCHECK(scope_type() == MODULE_SCOPE);
-  return ModuleInfo::cast(get(ModuleInfoIndex()));
-}
-
-String* ScopeInfo::ParameterName(int var) {
-  DCHECK_LE(0, var);
-  DCHECK_LT(var, ParameterCount());
-  int info_index = ParameterNamesIndex() + var;
-  return String::cast(get(info_index));
-}
-
-
-String* ScopeInfo::LocalName(int var) {
-  DCHECK_LE(0, var);
-  DCHECK_LT(var, LocalCount());
-  DCHECK(StackLocalNamesIndex() + StackLocalCount() ==
-         ContextLocalNamesIndex());
-  int info_index = StackLocalNamesIndex() + var;
-  return String::cast(get(info_index));
-}
-
-
-String* ScopeInfo::StackLocalName(int var) {
-  DCHECK_LE(0, var);
-  DCHECK_LT(var, StackLocalCount());
-  int info_index = StackLocalNamesIndex() + var;
-  return String::cast(get(info_index));
-}
-
-
-int ScopeInfo::StackLocalIndex(int var) {
-  DCHECK_LE(0, var);
-  DCHECK_LT(var, StackLocalCount());
-  int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
-  return first_slot_index + var;
-}
-
-
-String* ScopeInfo::ContextLocalName(int var) {
-  DCHECK_LE(0, var);
-  DCHECK_LT(var, ContextLocalCount());
-  int info_index = ContextLocalNamesIndex() + var;
-  return String::cast(get(info_index));
-}
-
-
-VariableMode ScopeInfo::ContextLocalMode(int var) {
-  DCHECK_LE(0, var);
-  DCHECK_LT(var, ContextLocalCount());
-  int info_index = ContextLocalInfosIndex() + var;
-  int value = Smi::cast(get(info_index))->value();
-  return VariableModeField::decode(value);
-}
-
-
-InitializationFlag ScopeInfo::ContextLocalInitFlag(int var) {
-  DCHECK_LE(0, var);
-  DCHECK_LT(var, ContextLocalCount());
-  int info_index = ContextLocalInfosIndex() + var;
-  int value = Smi::cast(get(info_index))->value();
-  return InitFlagField::decode(value);
-}
-
-
-MaybeAssignedFlag ScopeInfo::ContextLocalMaybeAssignedFlag(int var) {
-  DCHECK_LE(0, var);
-  DCHECK_LT(var, ContextLocalCount());
-  int info_index = ContextLocalInfosIndex() + var;
-  int value = Smi::cast(get(info_index))->value();
-  return MaybeAssignedFlagField::decode(value);
-}
-
-bool ScopeInfo::VariableIsSynthetic(String* name) {
-  // There's currently no flag stored on the ScopeInfo to indicate that a
-  // variable is a compiler-introduced temporary. However, to avoid conflict
-  // with user declarations, the current temporaries like .generator_object and
-  // .result start with a dot, so we can use that as a flag. It's a hack!
-  return name->length() == 0 || name->Get(0) == '.' ||
-         name->Equals(name->GetHeap()->this_string());
-}
-
-
-int ScopeInfo::StackSlotIndex(String* name) {
-  DCHECK(name->IsInternalizedString());
-  if (length() > 0) {
-    int first_slot_index = Smi::cast(get(StackLocalFirstSlotIndex()))->value();
-    int start = StackLocalNamesIndex();
-    int end = start + StackLocalCount();
-    for (int i = start; i < end; ++i) {
-      if (name == get(i)) {
-        return i - start + first_slot_index;
-      }
-    }
-  }
-  return -1;
-}
-
-int ScopeInfo::ModuleIndex(Handle<String> name, VariableMode* mode,
-                           InitializationFlag* init_flag,
-                           MaybeAssignedFlag* maybe_assigned_flag) {
-  DCHECK_EQ(scope_type(), MODULE_SCOPE);
-  DCHECK(name->IsInternalizedString());
-  DCHECK_NOT_NULL(mode);
-  DCHECK_NOT_NULL(init_flag);
-  DCHECK_NOT_NULL(maybe_assigned_flag);
-
-  int module_vars_count = Smi::cast(get(ModuleVariableCountIndex()))->value();
-  int entry = ModuleVariablesIndex();
-  for (int i = 0; i < module_vars_count; ++i) {
-    if (*name == get(entry + kModuleVariableNameOffset)) {
-      int index;
-      ModuleVariable(i, nullptr, &index, mode, init_flag, maybe_assigned_flag);
-      return index;
-    }
-    entry += kModuleVariableEntryLength;
-  }
-
-  return 0;
-}
-
-int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
-                                Handle<String> name, VariableMode* mode,
-                                InitializationFlag* init_flag,
-                                MaybeAssignedFlag* maybe_assigned_flag) {
-  DCHECK(name->IsInternalizedString());
-  DCHECK_NOT_NULL(mode);
-  DCHECK_NOT_NULL(init_flag);
-  DCHECK_NOT_NULL(maybe_assigned_flag);
-
-  if (scope_info->length() > 0) {
-    ContextSlotCache* context_slot_cache =
-        scope_info->GetIsolate()->context_slot_cache();
-    int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
-                                            maybe_assigned_flag);
-    if (result != ContextSlotCache::kNotFound) {
-      DCHECK_LT(result, scope_info->ContextLength());
-      return result;
-    }
-
-    int start = scope_info->ContextLocalNamesIndex();
-    int end = start + scope_info->ContextLocalCount();
-    for (int i = start; i < end; ++i) {
-      if (*name == scope_info->get(i)) {
-        int var = i - start;
-        *mode = scope_info->ContextLocalMode(var);
-        *init_flag = scope_info->ContextLocalInitFlag(var);
-        *maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
-        result = Context::MIN_CONTEXT_SLOTS + var;
-
-        context_slot_cache->Update(scope_info, name, *mode, *init_flag,
-                                   *maybe_assigned_flag, result);
-        DCHECK_LT(result, scope_info->ContextLength());
-        return result;
-      }
-    }
-    // Cache as not found. Mode, init flag and maybe assigned flag don't matter.
-    context_slot_cache->Update(scope_info, name, TEMPORARY,
-                               kNeedsInitialization, kNotAssigned, -1);
-  }
-
-  return -1;
-}
-
-String* ScopeInfo::ContextSlotName(int slot_index) {
-  int const var = slot_index - Context::MIN_CONTEXT_SLOTS;
-  DCHECK_LE(0, var);
-  DCHECK_LT(var, ContextLocalCount());
-  return ContextLocalName(var);
-}
-
-
-int ScopeInfo::ParameterIndex(String* name) {
-  DCHECK(name->IsInternalizedString());
-  if (length() > 0) {
-    // We must read parameters from the end since for
-    // multiply declared parameters the value of the
-    // last declaration of that parameter is used
-    // inside a function (and thus we need to look
-    // at the last index). Was bug# 1110337.
-    int start = ParameterNamesIndex();
-    int end = start + ParameterCount();
-    for (int i = end - 1; i >= start; --i) {
-      if (name == get(i)) {
-        return i - start;
-      }
-    }
-  }
-  return -1;
-}
-
-
-int ScopeInfo::ReceiverContextSlotIndex() {
-  if (length() > 0 && ReceiverVariableField::decode(Flags()) == CONTEXT)
-    return Smi::cast(get(ReceiverInfoIndex()))->value();
-  return -1;
-}
-
-int ScopeInfo::FunctionContextSlotIndex(String* name) {
-  DCHECK(name->IsInternalizedString());
-  if (length() > 0) {
-    if (FunctionVariableField::decode(Flags()) == CONTEXT &&
-        FunctionName() == name) {
-      return Smi::cast(get(FunctionNameInfoIndex() + 1))->value();
-    }
-  }
-  return -1;
-}
-
-
-FunctionKind ScopeInfo::function_kind() {
-  return FunctionKindField::decode(Flags());
-}
-
-int ScopeInfo::ParameterNamesIndex() {
-  DCHECK_LT(0, length());
-  return kVariablePartIndex;
-}
-
-
-int ScopeInfo::StackLocalFirstSlotIndex() {
-  return ParameterNamesIndex() + ParameterCount();
-}
-
-int ScopeInfo::StackLocalNamesIndex() { return StackLocalFirstSlotIndex() + 1; }
-
-int ScopeInfo::ContextLocalNamesIndex() {
-  return StackLocalNamesIndex() + StackLocalCount();
-}
-
-int ScopeInfo::ContextLocalInfosIndex() {
-  return ContextLocalNamesIndex() + ContextLocalCount();
-}
-
-int ScopeInfo::ReceiverInfoIndex() {
-  return ContextLocalInfosIndex() + ContextLocalCount();
-}
-
-int ScopeInfo::FunctionNameInfoIndex() {
-  return ReceiverInfoIndex() + (HasAllocatedReceiver() ? 1 : 0);
-}
-
-int ScopeInfo::OuterScopeInfoIndex() {
-  return FunctionNameInfoIndex() + (HasFunctionName() ? 2 : 0);
-}
-
-int ScopeInfo::ModuleInfoIndex() {
-  return OuterScopeInfoIndex() + (HasOuterScopeInfo() ? 1 : 0);
-}
-
-int ScopeInfo::ModuleVariableCountIndex() { return ModuleInfoIndex() + 1; }
-
-int ScopeInfo::ModuleVariablesIndex() { return ModuleVariableCountIndex() + 1; }
-
-void ScopeInfo::ModuleVariable(int i, String** name, int* index,
-                               VariableMode* mode,
-                               InitializationFlag* init_flag,
-                               MaybeAssignedFlag* maybe_assigned_flag) {
-  DCHECK_LE(0, i);
-  DCHECK_LT(i, Smi::cast(get(ModuleVariableCountIndex()))->value());
-
-  int entry = ModuleVariablesIndex() + i * kModuleVariableEntryLength;
-  int properties =
-      Smi::cast(get(entry + kModuleVariablePropertiesOffset))->value();
-
-  if (name != nullptr) {
-    *name = String::cast(get(entry + kModuleVariableNameOffset));
-  }
-  if (index != nullptr) {
-    *index = Smi::cast(get(entry + kModuleVariableIndexOffset))->value();
-    DCHECK_NE(*index, 0);
-  }
-  if (mode != nullptr) {
-    *mode = VariableModeField::decode(properties);
-  }
-  if (init_flag != nullptr) {
-    *init_flag = InitFlagField::decode(properties);
-  }
-  if (maybe_assigned_flag != nullptr) {
-    *maybe_assigned_flag = MaybeAssignedFlagField::decode(properties);
-  }
-}
-
-#ifdef DEBUG
-
-static void PrintList(const char* list_name,
-                      int nof_internal_slots,
-                      int start,
-                      int end,
-                      ScopeInfo* scope_info) {
-  if (start < end) {
-    PrintF("\n  // %s\n", list_name);
-    if (nof_internal_slots > 0) {
-      PrintF("  %2d - %2d [internal slots]\n", 0 , nof_internal_slots - 1);
-    }
-    for (int i = nof_internal_slots; start < end; ++i, ++start) {
-      PrintF("  %2d ", i);
-      String::cast(scope_info->get(start))->ShortPrint();
-      PrintF("\n");
-    }
-  }
-}
-
-
-void ScopeInfo::Print() {
-  PrintF("ScopeInfo ");
-  if (HasFunctionName()) {
-    FunctionName()->ShortPrint();
-  } else {
-    PrintF("/* no function name */");
-  }
-  PrintF("{");
-
-  if (length() > 0) {
-    PrintList("parameters", 0, ParameterNamesIndex(),
-              ParameterNamesIndex() + ParameterCount(), this);
-    PrintList("stack slots", 0, StackLocalNamesIndex(),
-              StackLocalNamesIndex() + StackLocalCount(), this);
-    PrintList("context slots", Context::MIN_CONTEXT_SLOTS,
-              ContextLocalNamesIndex(),
-              ContextLocalNamesIndex() + ContextLocalCount(), this);
-    // TODO(neis): Print module stuff if present.
-  }
-
-  PrintF("}\n");
-}
-#endif  // DEBUG
-
-Handle<ModuleInfoEntry> ModuleInfoEntry::New(Isolate* isolate,
-                                             Handle<Object> export_name,
-                                             Handle<Object> local_name,
-                                             Handle<Object> import_name,
-                                             int module_request, int cell_index,
-                                             int beg_pos, int end_pos) {
-  Handle<ModuleInfoEntry> result = Handle<ModuleInfoEntry>::cast(
-      isolate->factory()->NewStruct(MODULE_INFO_ENTRY_TYPE));
-  result->set_export_name(*export_name);
-  result->set_local_name(*local_name);
-  result->set_import_name(*import_name);
-  result->set_module_request(module_request);
-  result->set_cell_index(cell_index);
-  result->set_beg_pos(beg_pos);
-  result->set_end_pos(end_pos);
-  return result;
-}
-
-Handle<ModuleInfo> ModuleInfo::New(Isolate* isolate, Zone* zone,
-                                   ModuleDescriptor* descr) {
-  // Serialize module requests.
-  Handle<FixedArray> module_requests = isolate->factory()->NewFixedArray(
-      static_cast<int>(descr->module_requests().size()));
-  for (const auto& elem : descr->module_requests()) {
-    module_requests->set(elem.second, *elem.first->string());
-  }
-
-  // Serialize special exports.
-  Handle<FixedArray> special_exports =
-      isolate->factory()->NewFixedArray(descr->special_exports().length());
-  {
-    int i = 0;
-    for (auto entry : descr->special_exports()) {
-      Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate);
-      special_exports->set(i++, *serialized_entry);
-    }
-  }
-
-  // Serialize namespace imports.
-  Handle<FixedArray> namespace_imports =
-      isolate->factory()->NewFixedArray(descr->namespace_imports().length());
-  {
-    int i = 0;
-    for (auto entry : descr->namespace_imports()) {
-      Handle<ModuleInfoEntry> serialized_entry = entry->Serialize(isolate);
-      namespace_imports->set(i++, *serialized_entry);
-    }
-  }
-
-  // Serialize regular exports.
-  Handle<FixedArray> regular_exports =
-      descr->SerializeRegularExports(isolate, zone);
-
-  // Serialize regular imports.
-  Handle<FixedArray> regular_imports = isolate->factory()->NewFixedArray(
-      static_cast<int>(descr->regular_imports().size()));
-  {
-    int i = 0;
-    for (const auto& elem : descr->regular_imports()) {
-      Handle<ModuleInfoEntry> serialized_entry =
-          elem.second->Serialize(isolate);
-      regular_imports->set(i++, *serialized_entry);
-    }
-  }
-
-  Handle<ModuleInfo> result = isolate->factory()->NewModuleInfo();
-  result->set(kModuleRequestsIndex, *module_requests);
-  result->set(kSpecialExportsIndex, *special_exports);
-  result->set(kRegularExportsIndex, *regular_exports);
-  result->set(kNamespaceImportsIndex, *namespace_imports);
-  result->set(kRegularImportsIndex, *regular_imports);
-  return result;
-}
-
-int ModuleInfo::RegularExportCount() const {
-  DCHECK_EQ(regular_exports()->length() % kRegularExportLength, 0);
-  return regular_exports()->length() / kRegularExportLength;
-}
-
-String* ModuleInfo::RegularExportLocalName(int i) const {
-  return String::cast(regular_exports()->get(i * kRegularExportLength +
-                                             kRegularExportLocalNameOffset));
-}
-
-int ModuleInfo::RegularExportCellIndex(int i) const {
-  return Smi::cast(regular_exports()->get(i * kRegularExportLength +
-                                          kRegularExportCellIndexOffset))
-      ->value();
-}
-
-FixedArray* ModuleInfo::RegularExportExportNames(int i) const {
-  return FixedArray::cast(regular_exports()->get(
-      i * kRegularExportLength + kRegularExportExportNamesOffset));
-}
-
-Handle<ModuleInfoEntry> ModuleInfo::LookupRegularImport(
-    Handle<ModuleInfo> info, Handle<String> local_name) {
-  Isolate* isolate = info->GetIsolate();
-  Handle<FixedArray> regular_imports(info->regular_imports(), isolate);
-  for (int i = 0, n = regular_imports->length(); i < n; ++i) {
-    Handle<ModuleInfoEntry> entry(
-        ModuleInfoEntry::cast(regular_imports->get(i)), isolate);
-    if (String::cast(entry->local_name())->Equals(*local_name)) {
-      return entry;
-    }
-  }
-  UNREACHABLE();
-  return Handle<ModuleInfoEntry>();
-}
-
-}  // namespace internal
-}  // namespace v8
diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc
index c1679a4..225793c 100644
--- a/src/ast/scopes.cc
+++ b/src/ast/scopes.cc
@@ -9,12 +9,29 @@
 #include "src/accessors.h"
 #include "src/ast/ast.h"
 #include "src/bootstrapper.h"
+#include "src/counters.h"
 #include "src/messages.h"
+#include "src/objects-inl.h"
+#include "src/objects/module-info.h"
+#include "src/objects/scope-info.h"
 #include "src/parsing/parse-info.h"
+#include "src/parsing/preparsed-scope-data.h"
 
 namespace v8 {
 namespace internal {
 
+namespace {
+void* kDummyPreParserVariable = reinterpret_cast<void*>(0x1);
+void* kDummyPreParserLexicalVariable = reinterpret_cast<void*>(0x2);
+
+bool IsLexical(Variable* variable) {
+  if (variable == kDummyPreParserLexicalVariable) return true;
+  if (variable == kDummyPreParserVariable) return false;
+  return IsLexicalVariableMode(variable->mode());
+}
+
+}  // namespace
+
 // ----------------------------------------------------------------------------
 // Implementation of LocalsMap
 //
@@ -49,6 +66,20 @@
   return reinterpret_cast<Variable*>(p->value);
 }
 
+Variable* VariableMap::DeclareName(Zone* zone, const AstRawString* name,
+                                   VariableMode mode) {
+  Entry* p =
+      ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
+                                  ZoneAllocationPolicy(zone));
+  if (p->value == nullptr) {
+    // The variable has not been declared yet -> insert it.
+    DCHECK_EQ(name, p->key);
+    p->value =
+        mode == VAR ? kDummyPreParserVariable : kDummyPreParserLexicalVariable;
+  }
+  return reinterpret_cast<Variable*>(p->value);
+}
+
 void VariableMap::Remove(Variable* var) {
   const AstRawString* name = var->raw_name();
   ZoneHashMap::Remove(const_cast<AstRawString*>(name), name->hash());
@@ -74,21 +105,27 @@
   return NULL;
 }
 
+void SloppyBlockFunctionMap::Delegate::set_statement(Statement* statement) {
+  if (statement_ != nullptr) {
+    statement_->set_statement(statement);
+  }
+}
+
 SloppyBlockFunctionMap::SloppyBlockFunctionMap(Zone* zone)
     : ZoneHashMap(8, ZoneAllocationPolicy(zone)) {}
 
-void SloppyBlockFunctionMap::Declare(Zone* zone, const AstRawString* name,
-                                     SloppyBlockFunctionStatement* stmt) {
+void SloppyBlockFunctionMap::Declare(
+    Zone* zone, const AstRawString* name,
+    SloppyBlockFunctionMap::Delegate* delegate) {
   // AstRawStrings are unambiguous, i.e., the same string is always represented
   // by the same AstRawString*.
   Entry* p =
       ZoneHashMap::LookupOrInsert(const_cast<AstRawString*>(name), name->hash(),
                                   ZoneAllocationPolicy(zone));
-  stmt->set_next(static_cast<SloppyBlockFunctionStatement*>(p->value));
-  p->value = stmt;
+  delegate->set_next(static_cast<SloppyBlockFunctionMap::Delegate*>(p->value));
+  p->value = delegate;
 }
 
-
 // ----------------------------------------------------------------------------
 // Implementation of Scope
 
@@ -243,8 +280,7 @@
   // Cache the catch variable, even though it's also available via the
   // scope_info, as the parser expects that a catch scope always has the catch
   // variable as first and only variable.
-  Variable* variable = Declare(zone, this, catch_variable_name, VAR,
-                               NORMAL_VARIABLE, kCreatedInitialized);
+  Variable* variable = Declare(zone, catch_variable_name, VAR);
   AllocateHeapSlot(variable);
 }
 
@@ -261,9 +297,16 @@
   new_target_ = nullptr;
   function_ = nullptr;
   arguments_ = nullptr;
-  this_function_ = nullptr;
+  rare_data_ = nullptr;
   should_eager_compile_ = false;
-  is_lazily_parsed_ = false;
+  was_lazily_parsed_ = false;
+#ifdef DEBUG
+  DeclarationScope* outer_declaration_scope =
+      outer_scope_ ? outer_scope_->GetDeclarationScope() : nullptr;
+  is_being_lazily_parsed_ =
+      outer_declaration_scope ? outer_declaration_scope->is_being_lazily_parsed_
+                              : false;
+#endif
 }
 
 void Scope::SetDefaults() {
@@ -305,7 +348,7 @@
 }
 
 void DeclarationScope::set_should_eager_compile() {
-  should_eager_compile_ = !is_lazily_parsed_;
+  should_eager_compile_ = !was_lazily_parsed_;
 }
 
 void DeclarationScope::set_asm_module() {
@@ -354,17 +397,16 @@
       }
       DCHECK(!scope_info->HasOuterScopeInfo());
       break;
-    } else if (scope_info->scope_type() == FUNCTION_SCOPE ||
-               scope_info->scope_type() == EVAL_SCOPE) {
-      // TODO(neis): For an eval scope, we currently create an ordinary function
-      // context.  This is wrong and needs to be fixed.
-      // https://bugs.chromium.org/p/v8/issues/detail?id=5295
+    } else if (scope_info->scope_type() == FUNCTION_SCOPE) {
       outer_scope =
           new (zone) DeclarationScope(zone, FUNCTION_SCOPE, handle(scope_info));
       if (scope_info->IsAsmFunction())
         outer_scope->AsDeclarationScope()->set_asm_function();
       if (scope_info->IsAsmModule())
         outer_scope->AsDeclarationScope()->set_asm_module();
+    } else if (scope_info->scope_type() == EVAL_SCOPE) {
+      outer_scope =
+          new (zone) DeclarationScope(zone, EVAL_SCOPE, handle(scope_info));
     } else if (scope_info->scope_type() == BLOCK_SCOPE) {
       if (scope_info->is_declaration_scope()) {
         outer_scope =
@@ -424,11 +466,21 @@
   return is_declaration_scope() ? AsDeclarationScope()->num_parameters() : 0;
 }
 
+void DeclarationScope::DeclareSloppyBlockFunction(
+    const AstRawString* name, Scope* scope,
+    SloppyBlockFunctionStatement* statement) {
+  auto* delegate =
+      new (zone()) SloppyBlockFunctionMap::Delegate(scope, statement);
+  sloppy_block_function_map_.Declare(zone(), name, delegate);
+}
+
 void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) {
   DCHECK(is_sloppy(language_mode()));
   DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() ||
          (is_block_scope() && outer_scope()->is_function_scope()));
-  DCHECK(HasSimpleParameters() || is_block_scope());
+  DCHECK(HasSimpleParameters() || is_block_scope() || is_being_lazily_parsed_);
+  DCHECK_EQ(factory == nullptr, is_being_lazily_parsed_);
+
   bool has_simple_parameters = HasSimpleParameters();
   // For each variable which is used as a function declaration in a sloppy
   // block,
@@ -457,10 +509,10 @@
       }
     }
 
-    bool var_created = false;
+    Variable* created_variable = nullptr;
 
     // Write in assignments to var for each block-scoped function declaration
-    auto delegates = static_cast<SloppyBlockFunctionStatement*>(p->value);
+    auto delegates = static_cast<SloppyBlockFunctionMap::Delegate*>(p->value);
 
     DeclarationScope* decl_scope = this;
     while (decl_scope->is_eval_scope()) {
@@ -468,7 +520,7 @@
     }
     Scope* outer_scope = decl_scope->outer_scope();
 
-    for (SloppyBlockFunctionStatement* delegate = delegates;
+    for (SloppyBlockFunctionMap::Delegate* delegate = delegates;
          delegate != nullptr; delegate = delegate->next()) {
       // Check if there's a conflict with a lexical declaration
       Scope* query_scope = delegate->scope()->outer_scope();
@@ -482,7 +534,7 @@
       // `{ let e; try {} catch (e) { function e(){} } }`
       do {
         var = query_scope->LookupLocal(name);
-        if (var != nullptr && IsLexicalVariableMode(var->mode())) {
+        if (var != nullptr && IsLexical(var)) {
           should_hoist = false;
           break;
         }
@@ -492,32 +544,47 @@
       if (!should_hoist) continue;
 
       // Declare a var-style binding for the function in the outer scope
-      if (!var_created) {
-        var_created = true;
-        VariableProxy* proxy = factory->NewVariableProxy(name, NORMAL_VARIABLE);
-        Declaration* declaration =
-            factory->NewVariableDeclaration(proxy, this, kNoSourcePosition);
-        // Based on the preceding check, it doesn't matter what we pass as
-        // allow_harmony_restrictive_generators and
-        // sloppy_mode_block_scope_function_redefinition.
-        bool ok = true;
-        DeclareVariable(declaration, VAR,
-                        Variable::DefaultInitializationFlag(VAR), false,
-                        nullptr, &ok);
-        CHECK(ok);  // Based on the preceding check, this should not fail
-      }
+      if (factory) {
+        DCHECK(!is_being_lazily_parsed_);
+        if (created_variable == nullptr) {
+          VariableProxy* proxy =
+              factory->NewVariableProxy(name, NORMAL_VARIABLE);
+          auto declaration =
+              factory->NewVariableDeclaration(proxy, this, kNoSourcePosition);
+          // Based on the preceding check, it doesn't matter what we pass as
+          // allow_harmony_restrictive_generators and
+          // sloppy_mode_block_scope_function_redefinition.
+          bool ok = true;
+          created_variable = DeclareVariable(
+              declaration, VAR, Variable::DefaultInitializationFlag(VAR), false,
+              nullptr, &ok);
+          CHECK(ok);  // Based on the preceding check, this should not fail
+        }
 
-      Expression* assignment = factory->NewAssignment(
-          Token::ASSIGN, NewUnresolved(factory, name),
-          delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition);
-      Statement* statement =
-          factory->NewExpressionStatement(assignment, kNoSourcePosition);
-      delegate->set_statement(statement);
+        Expression* assignment = factory->NewAssignment(
+            Token::ASSIGN, NewUnresolved(factory, name),
+            delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition);
+        Statement* statement =
+            factory->NewExpressionStatement(assignment, kNoSourcePosition);
+        delegate->set_statement(statement);
+      } else {
+        DCHECK(is_being_lazily_parsed_);
+        if (created_variable == nullptr) {
+          created_variable = DeclareVariableName(name, VAR);
+          if (created_variable != kDummyPreParserVariable &&
+              created_variable != kDummyPreParserLexicalVariable) {
+            DCHECK(FLAG_preparser_scope_analysis);
+            created_variable->set_maybe_assigned();
+          }
+        }
+      }
     }
   }
 }
 
 void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) {
+  RuntimeCallTimerScope runtimeTimer(info->isolate(),
+                                     &RuntimeCallStats::CompileScopeAnalysis);
   DCHECK(info->literal() != NULL);
   DeclarationScope* scope = info->literal()->scope();
 
@@ -542,13 +609,15 @@
     scope->HoistSloppyBlockFunctions(&factory);
   }
 
-  // We are compiling one of three cases:
+  // We are compiling one of four cases:
   // 1) top-level code,
   // 2) a function/eval/module on the top-level
   // 3) a function/eval in a scope that was already resolved.
+  // 4) an asm.js function
   DCHECK(scope->scope_type() == SCRIPT_SCOPE ||
          scope->outer_scope()->scope_type() == SCRIPT_SCOPE ||
-         scope->outer_scope()->already_resolved_);
+         scope->outer_scope()->already_resolved_ ||
+         (info->asm_function_scope() && scope->is_function_scope()));
 
   // The outer scope is never lazy.
   scope->set_should_eager_compile();
@@ -565,6 +634,7 @@
 #ifdef DEBUG
   if (info->script_is_native() ? FLAG_print_builtin_scopes
                                : FLAG_print_scopes) {
+    PrintF("Global scope:\n");
     scope->Print();
   }
   scope->CheckScopePositions();
@@ -577,11 +647,11 @@
   DCHECK(is_declaration_scope());
   DCHECK(has_this_declaration());
 
-  bool subclass_constructor = IsSubclassConstructor(function_kind_);
-  Variable* var = Declare(
-      zone(), this, ast_value_factory->this_string(),
-      subclass_constructor ? CONST : VAR, THIS_VARIABLE,
-      subclass_constructor ? kNeedsInitialization : kCreatedInitialized);
+  bool derived_constructor = IsDerivedConstructor(function_kind_);
+  Variable* var =
+      Declare(zone(), ast_value_factory->this_string(),
+              derived_constructor ? CONST : VAR, THIS_VARIABLE,
+              derived_constructor ? kNeedsInitialization : kCreatedInitialized);
   receiver_ = var;
 }
 
@@ -594,9 +664,8 @@
     // Declare 'arguments' variable which exists in all non arrow functions.
     // Note that it might never be accessed, in which case it won't be
     // allocated during variable allocation.
-    arguments_ = Declare(zone(), this, ast_value_factory->arguments_string(),
-                         VAR, NORMAL_VARIABLE, kCreatedInitialized);
-  } else if (IsLexicalVariableMode(arguments_->mode())) {
+    arguments_ = Declare(zone(), ast_value_factory->arguments_string(), VAR);
+  } else if (IsLexical(arguments_)) {
     // Check if there's lexically declared variable named arguments to avoid
     // redeclaration. See ES#sec-functiondeclarationinstantiation, step 20.
     arguments_ = nullptr;
@@ -609,14 +678,12 @@
   DCHECK(!is_arrow_scope());
 
   DeclareThis(ast_value_factory);
-  new_target_ = Declare(zone(), this, ast_value_factory->new_target_string(),
-                        CONST, NORMAL_VARIABLE, kCreatedInitialized);
+  new_target_ = Declare(zone(), ast_value_factory->new_target_string(), CONST);
 
   if (IsConciseMethod(function_kind_) || IsClassConstructor(function_kind_) ||
       IsAccessorFunction(function_kind_)) {
-    this_function_ =
-        Declare(zone(), this, ast_value_factory->this_function_string(), CONST,
-                NORMAL_VARIABLE, kCreatedInitialized);
+    EnsureRareData()->this_function =
+        Declare(zone(), ast_value_factory->this_function_string(), CONST);
   }
 }
 
@@ -636,24 +703,32 @@
   return function_;
 }
 
+Variable* DeclarationScope::DeclareGeneratorObjectVar(
+    const AstRawString* name) {
+  DCHECK(is_function_scope() || is_module_scope());
+  DCHECK_NULL(generator_object_var());
+
+  Variable* result = EnsureRareData()->generator_object =
+      NewTemporary(name, kNotAssigned);
+  result->set_is_used();
+  return result;
+}
+
+Variable* DeclarationScope::DeclarePromiseVar(const AstRawString* name) {
+  DCHECK(is_function_scope());
+  DCHECK_NULL(promise_var());
+  Variable* result = EnsureRareData()->promise = NewTemporary(name);
+  result->set_is_used();
+  return result;
+}
+
 bool Scope::HasBeenRemoved() const {
-  // TODO(neis): Store this information somewhere instead of calculating it.
-
-  if (!is_block_scope()) return false;  // Shortcut.
-
-  Scope* parent = outer_scope();
-  if (parent == nullptr) {
-    DCHECK(is_script_scope());
-    return false;
+  if (sibling() == this) {
+    DCHECK_NULL(inner_scope_);
+    DCHECK(is_block_scope());
+    return true;
   }
-
-  Scope* sibling = parent->inner_scope();
-  for (; sibling != nullptr; sibling = sibling->sibling()) {
-    if (sibling == this) return false;
-  }
-
-  DCHECK_NULL(inner_scope_);
-  return true;
+  return false;
 }
 
 Scope* Scope::GetUnremovedScope() {
@@ -667,6 +742,7 @@
 
 Scope* Scope::FinalizeBlockScope() {
   DCHECK(is_block_scope());
+  DCHECK(!HasBeenRemoved());
 
   if (variables_.occupancy() > 0 ||
       (is_declaration_scope() && calls_sloppy_eval())) {
@@ -705,7 +781,12 @@
   PropagateUsageFlagsToScope(outer_scope_);
   // This block does not need a context.
   num_heap_slots_ = 0;
-  return NULL;
+
+  // Mark scope as removed by making it its own sibling.
+  sibling_ = this;
+  DCHECK(HasBeenRemoved());
+
+  return nullptr;
 }
 
 void DeclarationScope::AddLocal(Variable* var) {
@@ -715,13 +796,13 @@
   locals_.Add(var);
 }
 
-Variable* Scope::Declare(Zone* zone, Scope* scope, const AstRawString* name,
+Variable* Scope::Declare(Zone* zone, const AstRawString* name,
                          VariableMode mode, VariableKind kind,
                          InitializationFlag initialization_flag,
                          MaybeAssignedFlag maybe_assigned_flag) {
   bool added;
   Variable* var =
-      variables_.Declare(zone, scope, name, mode, kind, initialization_flag,
+      variables_.Declare(zone, this, name, mode, kind, initialization_flag,
                          maybe_assigned_flag, &added);
   if (added) locals_.Add(var);
   return var;
@@ -796,6 +877,7 @@
   DCHECK(!already_resolved_);
   DCHECK(!other->already_resolved_);
   if (calls_eval()) other->RecordEvalCall();
+  if (inner_scope_calls_eval_) other->inner_scope_calls_eval_ = true;
 }
 
 Variable* Scope::LookupInScopeInfo(const AstRawString* name) {
@@ -869,12 +951,14 @@
   DCHECK(is_function_scope() || is_module_scope());
   DCHECK(!has_rest_);
   DCHECK(!is_optional || !is_rest);
+  DCHECK(!is_being_lazily_parsed_);
+  DCHECK(!was_lazily_parsed_);
   Variable* var;
   if (mode == TEMPORARY) {
     var = NewTemporary(name);
   } else {
-    var =
-        Declare(zone(), this, name, mode, NORMAL_VARIABLE, kCreatedInitialized);
+    DCHECK_EQ(mode, VAR);
+    var = Declare(zone(), name, mode);
     // TODO(wingo): Avoid O(n^2) check.
     *is_duplicate = IsDeclaredParameter(name);
   }
@@ -886,6 +970,26 @@
   return var;
 }
 
+Variable* DeclarationScope::DeclareParameterName(
+    const AstRawString* name, bool is_rest,
+    AstValueFactory* ast_value_factory) {
+  DCHECK(!already_resolved_);
+  DCHECK(is_function_scope() || is_module_scope());
+  DCHECK(!has_rest_ || is_rest);
+  DCHECK(is_being_lazily_parsed_);
+  has_rest_ = is_rest;
+  if (name == ast_value_factory->arguments_string()) {
+    has_arguments_parameter_ = true;
+  }
+  if (FLAG_preparser_scope_analysis) {
+    Variable* var = Declare(zone(), name, VAR);
+    params_.Add(var, zone());
+    return var;
+  }
+  DeclareVariableName(name, VAR);
+  return nullptr;
+}
+
 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode,
                               InitializationFlag init_flag, VariableKind kind,
                               MaybeAssignedFlag maybe_assigned_flag) {
@@ -894,8 +998,10 @@
   // introduced during variable allocation, and TEMPORARY variables are
   // allocated via NewTemporary().
   DCHECK(IsDeclaredVariableMode(mode));
-  return Declare(zone(), this, name, mode, kind, init_flag,
-                 maybe_assigned_flag);
+  DCHECK_IMPLIES(GetDeclarationScope()->is_being_lazily_parsed(),
+                 mode == VAR || mode == LET || mode == CONST);
+  DCHECK(!GetDeclarationScope()->was_lazily_parsed());
+  return Declare(zone(), name, mode, kind, init_flag, maybe_assigned_flag);
 }
 
 Variable* Scope::DeclareVariable(
@@ -904,6 +1010,8 @@
     bool* sloppy_mode_block_scope_function_redefinition, bool* ok) {
   DCHECK(IsDeclaredVariableMode(mode));
   DCHECK(!already_resolved_);
+  DCHECK(!GetDeclarationScope()->is_being_lazily_parsed());
+  DCHECK(!GetDeclarationScope()->was_lazily_parsed());
 
   if (mode == VAR && !is_declaration_scope()) {
     return GetDeclarationScope()->DeclareVariable(
@@ -920,15 +1028,25 @@
   const AstRawString* name = proxy->raw_name();
   bool is_function_declaration = declaration->IsFunctionDeclaration();
 
+  // Pessimistically assume that top-level variables will be assigned.
+  //
+  // Top-level variables in a script can be accessed by other scripts or even
+  // become global properties. While this does not apply to top-level variables
+  // in a module (assuming they are not exported), we must still mark these as
+  // assigned because they might be accessed by a lazily parsed top-level
+  // function, which, for efficiency, we preparse without variable tracking.
+  if (is_script_scope() || is_module_scope()) {
+    if (mode != CONST) proxy->set_is_assigned();
+  }
+
   Variable* var = nullptr;
   if (is_eval_scope() && is_sloppy(language_mode()) && mode == VAR) {
     // In a var binding in a sloppy direct eval, pollute the enclosing scope
     // with this new binding by doing the following:
     // The proxy is bound to a lookup variable to force a dynamic declaration
     // using the DeclareEvalVar or DeclareEvalFunction runtime functions.
-    VariableKind kind = NORMAL_VARIABLE;
-    // TODO(sigurds) figure out if kNotAssigned is OK here
-    var = new (zone()) Variable(this, name, mode, kind, init, kNotAssigned);
+    var = new (zone())
+        Variable(this, name, mode, NORMAL_VARIABLE, init, kMaybeAssigned);
     var->AllocateTo(VariableLocation::LOOKUP, -1);
   } else {
     // Declare the variable in the declaration scope.
@@ -1002,6 +1120,43 @@
   return var;
 }
 
+Variable* Scope::DeclareVariableName(const AstRawString* name,
+                                     VariableMode mode) {
+  DCHECK(IsDeclaredVariableMode(mode));
+  DCHECK(!already_resolved_);
+  DCHECK(GetDeclarationScope()->is_being_lazily_parsed());
+
+  if (mode == VAR && !is_declaration_scope()) {
+    return GetDeclarationScope()->DeclareVariableName(name, mode);
+  }
+  DCHECK(!is_with_scope());
+  DCHECK(!is_eval_scope());
+  // Unlike DeclareVariable, DeclareVariableName allows declaring variables in
+  // catch scopes: Parser::RewriteCatchPattern bypasses DeclareVariable by
+  // calling DeclareLocal directly, and it doesn't make sense to add a similar
+  // bypass mechanism for PreParser.
+  DCHECK(is_declaration_scope() || (IsLexicalVariableMode(mode) &&
+                                    (is_block_scope() || is_catch_scope())));
+  DCHECK(scope_info_.is_null());
+
+  // Declare the variable in the declaration scope.
+  if (FLAG_preparser_scope_analysis) {
+    Variable* var = LookupLocal(name);
+    DCHECK_NE(var, kDummyPreParserLexicalVariable);
+    DCHECK_NE(var, kDummyPreParserVariable);
+    if (var == nullptr) {
+      var = DeclareLocal(name, mode);
+    } else if (mode == VAR) {
+      DCHECK_EQ(var->mode(), VAR);
+      var->set_maybe_assigned();
+    }
+    var->set_is_used();
+    return var;
+  } else {
+    return variables_.DeclareName(zone(), name, mode);
+  }
+}
+
 VariableProxy* Scope::NewUnresolved(AstNodeFactory* factory,
                                     const AstRawString* name,
                                     int start_position, VariableKind kind) {
@@ -1009,7 +1164,7 @@
   // the same name because they may be removed selectively via
   // RemoveUnresolved().
   DCHECK(!already_resolved_);
-  DCHECK_EQ(!needs_migration_, factory->zone() == zone());
+  DCHECK_EQ(factory->zone(), zone());
   VariableProxy* proxy = factory->NewVariableProxy(name, kind, start_position);
   proxy->set_next_unresolved(unresolved_);
   unresolved_ = proxy;
@@ -1026,8 +1181,8 @@
 Variable* DeclarationScope::DeclareDynamicGlobal(const AstRawString* name,
                                                  VariableKind kind) {
   DCHECK(is_script_scope());
-  return variables_.Declare(zone(), this, name, DYNAMIC_GLOBAL, kind,
-                            kCreatedInitialized);
+  return variables_.Declare(zone(), this, name, DYNAMIC_GLOBAL, kind);
+  // TODO(neis): Mark variable as maybe-assigned?
 }
 
 
@@ -1050,31 +1205,17 @@
   return false;
 }
 
-bool Scope::RemoveUnresolved(const AstRawString* name) {
-  if (unresolved_ != nullptr && unresolved_->raw_name() == name) {
-    VariableProxy* removed = unresolved_;
-    unresolved_ = unresolved_->next_unresolved();
-    removed->set_next_unresolved(nullptr);
-    return true;
-  }
-  VariableProxy* current = unresolved_;
-  while (current != nullptr) {
-    VariableProxy* next = current->next_unresolved();
-    if (next != nullptr && next->raw_name() == name) {
-      current->set_next_unresolved(next->next_unresolved());
-      next->set_next_unresolved(nullptr);
-      return true;
-    }
-    current = next;
-  }
-  return false;
+Variable* Scope::NewTemporary(const AstRawString* name) {
+  return NewTemporary(name, kMaybeAssigned);
 }
 
-Variable* Scope::NewTemporary(const AstRawString* name) {
+Variable* Scope::NewTemporary(const AstRawString* name,
+                              MaybeAssignedFlag maybe_assigned) {
   DeclarationScope* scope = GetClosureScope();
   Variable* var = new (zone())
       Variable(scope, name, TEMPORARY, NORMAL_VARIABLE, kCreatedInitialized);
   scope->AddLocal(var);
+  if (maybe_assigned == kMaybeAssigned) var->set_maybe_assigned();
   return var;
 }
 
@@ -1157,9 +1298,9 @@
   // guaranteed to be correct.
   for (const Scope* s = this; s != outer; s = s->outer_scope_) {
     // Eval forces context allocation on all outer scopes, so we don't need to
-    // look at those scopes. Sloppy eval makes all top-level variables dynamic,
-    // whereas strict-mode requires context allocation.
-    if (s->is_eval_scope()) return !is_strict(s->language_mode());
+    // look at those scopes. Sloppy eval makes top-level non-lexical variables
+    // dynamic, whereas strict-mode requires context allocation.
+    if (s->is_eval_scope()) return is_sloppy(s->language_mode());
     // Catch scopes force context allocation of all variables.
     if (s->is_catch_scope()) continue;
     // With scopes do not introduce variables that need allocation.
@@ -1276,7 +1417,7 @@
 
 Handle<StringSet> DeclarationScope::CollectNonLocals(
     ParseInfo* info, Handle<StringSet> non_locals) {
-  VariableProxy* free_variables = FetchFreeVariables(this, true, info);
+  VariableProxy* free_variables = FetchFreeVariables(this, info);
   for (VariableProxy* proxy = free_variables; proxy != nullptr;
        proxy = proxy->next_unresolved()) {
     non_locals = StringSet::Add(non_locals, proxy->name());
@@ -1289,27 +1430,42 @@
   DCHECK(is_function_scope());
 
   // Reset all non-trivial members.
-  params_.Clear();
+  if (!aborted || !IsArrowFunction(function_kind_)) {
+    // Do not remove parameters when lazy parsing an Arrow Function has failed,
+    // as the formal parameters are not re-parsed.
+    params_.Clear();
+  }
   decls_.Clear();
   locals_.Clear();
-  sloppy_block_function_map_.Clear();
-  variables_.Clear();
-  // Make sure we won't walk the scope tree from here on.
   inner_scope_ = nullptr;
   unresolved_ = nullptr;
 
-  if (aborted && !IsArrowFunction(function_kind_)) {
-    DeclareDefaultFunctionVariables(ast_value_factory);
+  if (aborted) {
+    // Prepare scope for use in the outer zone.
+    zone_ = ast_value_factory->zone();
+    variables_.Reset(ZoneAllocationPolicy(zone_));
+    sloppy_block_function_map_.Reset(ZoneAllocationPolicy(zone_));
+    if (!IsArrowFunction(function_kind_)) {
+      DeclareDefaultFunctionVariables(ast_value_factory);
+    }
+  } else {
+    // Make sure this scope isn't used for allocation anymore.
+    zone_ = nullptr;
+    variables_.Invalidate();
+    sloppy_block_function_map_.Invalidate();
   }
 
 #ifdef DEBUG
   needs_migration_ = false;
+  is_being_lazily_parsed_ = false;
 #endif
 
-  is_lazily_parsed_ = !aborted;
+  was_lazily_parsed_ = !aborted;
 }
 
-void DeclarationScope::AnalyzePartially(AstNodeFactory* ast_node_factory) {
+void DeclarationScope::AnalyzePartially(
+    AstNodeFactory* ast_node_factory,
+    PreParsedScopeData* preparsed_scope_data) {
   DCHECK(!force_eager_compilation_);
   VariableProxy* unresolved = nullptr;
 
@@ -1317,9 +1473,8 @@
     // Try to resolve unresolved variables for this Scope and migrate those
     // which cannot be resolved inside. It doesn't make sense to try to resolve
     // them in the outer Scopes here, because they are incomplete.
-    for (VariableProxy* proxy =
-             FetchFreeVariables(this, !FLAG_lazy_inner_functions);
-         proxy != nullptr; proxy = proxy->next_unresolved()) {
+    for (VariableProxy* proxy = FetchFreeVariables(this); proxy != nullptr;
+         proxy = proxy->next_unresolved()) {
       DCHECK(!proxy->is_resolved());
       VariableProxy* copy = ast_node_factory->CopyVariableProxy(proxy);
       copy->set_next_unresolved(unresolved);
@@ -1331,7 +1486,20 @@
         !(MustAllocate(arguments_) && !has_arguments_parameter_)) {
       arguments_ = nullptr;
     }
+
+    if (FLAG_preparser_scope_analysis) {
+      // Decide context allocation for the locals and parameters and store the
+      // info away.
+      AllocateVariablesRecursively();
+      CollectVariableData(preparsed_scope_data);
+    }
   }
+#ifdef DEBUG
+  if (FLAG_print_scopes) {
+    PrintF("Inner function scope:\n");
+    Print();
+  }
+#endif
 
   ResetAfterPreparsing(ast_node_factory->ast_value_factory(), false);
 
@@ -1339,8 +1507,10 @@
 }
 
 #ifdef DEBUG
-static const char* Header(ScopeType scope_type, FunctionKind function_kind,
-                          bool is_declaration_scope) {
+namespace {
+
+const char* Header(ScopeType scope_type, FunctionKind function_kind,
+                   bool is_declaration_scope) {
   switch (scope_type) {
     case EVAL_SCOPE: return "eval";
     // TODO(adamk): Should we print concise method scopes specially?
@@ -1359,18 +1529,13 @@
   return NULL;
 }
 
+void Indent(int n, const char* str) { PrintF("%*s%s", n, "", str); }
 
-static void Indent(int n, const char* str) {
-  PrintF("%*s%s", n, "", str);
-}
-
-
-static void PrintName(const AstRawString* name) {
+void PrintName(const AstRawString* name) {
   PrintF("%.*s", name->length(), name->raw_data());
 }
 
-
-static void PrintLocation(Variable* var) {
+void PrintLocation(Variable* var) {
   switch (var->location()) {
     case VariableLocation::UNALLOCATED:
       break;
@@ -1392,45 +1557,52 @@
   }
 }
 
-
-static void PrintVar(int indent, Variable* var) {
-  if (var->is_used() || !var->IsUnallocated()) {
-    Indent(indent, VariableMode2String(var->mode()));
-    PrintF(" ");
-    if (var->raw_name()->IsEmpty())
-      PrintF(".%p", reinterpret_cast<void*>(var));
-    else
-      PrintName(var->raw_name());
-    PrintF(";  // ");
-    PrintLocation(var);
-    bool comma = !var->IsUnallocated();
-    if (var->has_forced_context_allocation()) {
-      if (comma) PrintF(", ");
-      PrintF("forced context allocation");
-      comma = true;
-    }
-    if (var->maybe_assigned() == kNotAssigned) {
-      if (comma) PrintF(", ");
-      PrintF("never assigned");
-    }
-    PrintF("\n");
+void PrintVar(int indent, Variable* var) {
+  Indent(indent, VariableMode2String(var->mode()));
+  PrintF(" ");
+  if (var->raw_name()->IsEmpty())
+    PrintF(".%p", reinterpret_cast<void*>(var));
+  else
+    PrintName(var->raw_name());
+  PrintF(";  // ");
+  PrintLocation(var);
+  bool comma = !var->IsUnallocated();
+  if (var->has_forced_context_allocation()) {
+    if (comma) PrintF(", ");
+    PrintF("forced context allocation");
+    comma = true;
   }
+  if (var->maybe_assigned() == kNotAssigned) {
+    if (comma) PrintF(", ");
+    PrintF("never assigned");
+  }
+  PrintF("\n");
 }
 
-static void PrintMap(int indent, VariableMap* map, bool locals) {
+void PrintMap(int indent, const char* label, VariableMap* map, bool locals,
+              Variable* function_var) {
+  bool printed_label = false;
   for (VariableMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
     Variable* var = reinterpret_cast<Variable*>(p->value);
+    if (var == function_var) continue;
+    if (var == kDummyPreParserVariable ||
+        var == kDummyPreParserLexicalVariable) {
+      continue;
+    }
     bool local = !IsDynamicVariableMode(var->mode());
-    if (locals ? local : !local) {
-      if (var == nullptr) {
-        Indent(indent, "<?>\n");
-      } else {
-        PrintVar(indent, var);
+    if ((locals ? local : !local) &&
+        (var->is_used() || !var->IsUnallocated())) {
+      if (!printed_label) {
+        Indent(indent, label);
+        printed_label = true;
       }
+      PrintVar(indent, var);
     }
   }
 }
 
+}  // anonymous namespace
+
 void DeclarationScope::PrintParameters() {
   PrintF(" (");
   for (int i = 0; i < params_.length(); i++) {
@@ -1466,6 +1638,9 @@
   }
 
   PrintF(" { // (%d, %d)\n", start_position(), end_position());
+  if (is_hidden()) {
+    Indent(n1, "// is hidden\n");
+  }
 
   // Function name, if any (named function literals, only).
   if (function != nullptr) {
@@ -1487,9 +1662,12 @@
   if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
   if (is_declaration_scope()) {
     DeclarationScope* scope = AsDeclarationScope();
-    if (scope->is_lazily_parsed()) Indent(n1, "// lazily parsed\n");
+    if (scope->was_lazily_parsed()) Indent(n1, "// lazily parsed\n");
     if (scope->ShouldEagerCompile()) Indent(n1, "// will be compiled\n");
   }
+  if (has_forced_context_allocation()) {
+    Indent(n1, "// forces context allocation\n");
+  }
   if (num_stack_slots_ > 0) {
     Indent(n1, "// ");
     PrintF("%d stack slots\n", num_stack_slots_);
@@ -1505,12 +1683,22 @@
     PrintVar(n1, function);
   }
 
-  if (variables_.Start() != NULL) {
-    Indent(n1, "// local vars:\n");
-    PrintMap(n1, &variables_, true);
+  // Print temporaries.
+  {
+    bool printed_header = false;
+    for (Variable* local : locals_) {
+      if (local->mode() != TEMPORARY) continue;
+      if (!printed_header) {
+        printed_header = true;
+        Indent(n1, "// temporary vars:\n");
+      }
+      PrintVar(n1, local);
+    }
+  }
 
-    Indent(n1, "// dynamic vars:\n");
-    PrintMap(n1, &variables_, false);
+  if (variables_.occupancy() > 0) {
+    PrintMap(n1, "// local vars:\n", &variables_, true, function);
+    PrintMap(n1, "// dynamic vars:\n", &variables_, false, function);
   }
 
   // Print inner scopes (disable by providing negative n).
@@ -1539,6 +1727,12 @@
 void Scope::CheckZones() {
   DCHECK(!needs_migration_);
   for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
+    if (scope->is_declaration_scope() &&
+        scope->AsDeclarationScope()->was_lazily_parsed()) {
+      DCHECK_NULL(scope->zone());
+      DCHECK_NULL(scope->inner_scope_);
+      continue;
+    }
     CHECK_EQ(scope->zone(), zone());
     scope->CheckZones();
   }
@@ -1548,8 +1742,7 @@
 Variable* Scope::NonLocal(const AstRawString* name, VariableMode mode) {
   // Declare a new non-local.
   DCHECK(IsDynamicVariableMode(mode));
-  Variable* var = variables_.Declare(zone(), NULL, name, mode, NORMAL_VARIABLE,
-                                     kCreatedInitialized);
+  Variable* var = variables_.Declare(zone(), nullptr, name, mode);
   // Allocate it by giving it a dynamic lookup.
   var->AllocateTo(VariableLocation::LOOKUP, -1);
   return var;
@@ -1590,6 +1783,13 @@
   // The variable could not be resolved statically.
   if (var == nullptr) return var;
 
+  // TODO(marja): Separate LookupRecursive for preparsed scopes better.
+  if (var == kDummyPreParserVariable || var == kDummyPreParserLexicalVariable) {
+    DCHECK(GetDeclarationScope()->is_being_lazily_parsed());
+    DCHECK(FLAG_lazy_inner_functions);
+    return var;
+  }
+
   if (is_function_scope() && !var->is_dynamic()) {
     var->ForceContextAllocation();
   }
@@ -1641,34 +1841,20 @@
   DCHECK(!proxy->is_resolved());
   Variable* var = LookupRecursive(proxy, nullptr);
   ResolveTo(info, proxy, var);
-
-  if (FLAG_lazy_inner_functions) {
-    if (info != nullptr && info->is_native()) return;
-    // Pessimistically force context allocation for all variables to which inner
-    // scope variables could potentially resolve to.
-    Scope* scope = GetClosureScope()->outer_scope_;
-    while (scope != nullptr && scope->scope_info_.is_null()) {
-      var = scope->LookupLocal(proxy->raw_name());
-      if (var != nullptr) {
-        // Since we don't lazy parse inner arrow functions, inner functions
-        // cannot refer to the outer "this".
-        if (!var->is_dynamic() && !var->is_this() &&
-            !var->has_forced_context_allocation()) {
-          var->ForceContextAllocation();
-          var->set_is_used();
-          // We don't know what the (potentially lazy parsed) inner function
-          // does with the variable; pessimistically assume that it's assigned.
-          var->set_maybe_assigned();
-        }
-      }
-      scope = scope->outer_scope_;
-    }
-  }
 }
 
 namespace {
 
 bool AccessNeedsHoleCheck(Variable* var, VariableProxy* proxy, Scope* scope) {
+  if (var->mode() == DYNAMIC_LOCAL) {
+    // Dynamically introduced variables never need a hole check (since they're
+    // VAR bindings, either from var or function declarations), but the variable
+    // they shadow might need a hole check, which we want to do if we decide
+    // that no shadowing variable was dynamically introoduced.
+    DCHECK(!var->binding_needs_init());
+    return AccessNeedsHoleCheck(var->local_if_not_shadowed(), proxy, scope);
+  }
+
   if (!var->binding_needs_init()) {
     return false;
   }
@@ -1703,8 +1889,7 @@
   }
 
   if (var->is_this()) {
-    DCHECK(
-        IsSubclassConstructor(scope->GetDeclarationScope()->function_kind()));
+    DCHECK(IsDerivedConstructor(scope->GetDeclarationScope()->function_kind()));
     // TODO(littledan): implement 'this' hole check elimination.
     return true;
   }
@@ -1742,44 +1927,79 @@
 #endif
 
   DCHECK_NOT_NULL(var);
-  if (proxy->is_assigned()) var->set_maybe_assigned();
   if (AccessNeedsHoleCheck(var, proxy, this)) proxy->set_needs_hole_check();
   proxy->BindTo(var);
 }
 
 void Scope::ResolveVariablesRecursively(ParseInfo* info) {
   DCHECK(info->script_scope()->is_script_scope());
+  // Lazy parsed declaration scopes are already partially analyzed. If there are
+  // unresolved references remaining, they just need to be resolved in outer
+  // scopes.
+  if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) {
+    DCHECK(variables_.occupancy() == 0);
+    for (VariableProxy* proxy = unresolved_; proxy != nullptr;
+         proxy = proxy->next_unresolved()) {
+      Variable* var = outer_scope()->LookupRecursive(proxy, nullptr);
+      if (!var->is_dynamic()) {
+        var->set_is_used();
+        var->ForceContextAllocation();
+        if (proxy->is_assigned()) var->set_maybe_assigned();
+      }
+    }
+  } else {
+    // Resolve unresolved variables for this scope.
+    for (VariableProxy* proxy = unresolved_; proxy != nullptr;
+         proxy = proxy->next_unresolved()) {
+      ResolveVariable(info, proxy);
+    }
 
-  // Resolve unresolved variables for this scope.
-  for (VariableProxy* proxy = unresolved_; proxy != nullptr;
-       proxy = proxy->next_unresolved()) {
-    ResolveVariable(info, proxy);
-  }
-
-  // Resolve unresolved variables for inner scopes.
-  for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
-    scope->ResolveVariablesRecursively(info);
+    // Resolve unresolved variables for inner scopes.
+    for (Scope* scope = inner_scope_; scope != nullptr;
+         scope = scope->sibling_) {
+      scope->ResolveVariablesRecursively(info);
+    }
   }
 }
 
 VariableProxy* Scope::FetchFreeVariables(DeclarationScope* max_outer_scope,
-                                         bool try_to_resolve, ParseInfo* info,
+                                         ParseInfo* info,
                                          VariableProxy* stack) {
+  // Module variables must be allocated before variable resolution
+  // to ensure that AccessNeedsHoleCheck() can detect import variables.
+  if (info != nullptr && is_module_scope()) {
+    AsModuleScope()->AllocateModuleVariables();
+  }
+  // Lazy parsed declaration scopes are already partially analyzed. If there are
+  // unresolved references remaining, they just need to be resolved in outer
+  // scopes.
+  Scope* lookup =
+      is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()
+          ? outer_scope()
+          : this;
   for (VariableProxy *proxy = unresolved_, *next = nullptr; proxy != nullptr;
        proxy = next) {
     next = proxy->next_unresolved();
     DCHECK(!proxy->is_resolved());
-    Variable* var = nullptr;
-    if (try_to_resolve) {
-      var = LookupRecursive(proxy, max_outer_scope->outer_scope());
-    }
+    Variable* var =
+        lookup->LookupRecursive(proxy, max_outer_scope->outer_scope());
     if (var == nullptr) {
       proxy->set_next_unresolved(stack);
       stack = proxy;
-    } else if (info != nullptr) {
-      ResolveTo(info, proxy, var);
-    } else {
-      var->set_is_used();
+    } else if (var != kDummyPreParserVariable &&
+               var != kDummyPreParserLexicalVariable) {
+      if (info != nullptr) {
+        // In this case we need to leave scopes in a way that they can be
+        // allocated. If we resolved variables from lazy parsed scopes, we need
+        // to context allocate the var.
+        ResolveTo(info, proxy, var);
+        if (!var->is_dynamic() && lookup != this) var->ForceContextAllocation();
+      } else {
+        var->set_is_used();
+        if (proxy->is_assigned()) {
+          var->set_maybe_assigned();
+        }
+      }
     }
   }
 
@@ -1787,14 +2007,16 @@
   unresolved_ = nullptr;
 
   for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
-    stack =
-        scope->FetchFreeVariables(max_outer_scope, try_to_resolve, info, stack);
+    stack = scope->FetchFreeVariables(max_outer_scope, info, stack);
   }
 
   return stack;
 }
 
 bool Scope::MustAllocate(Variable* var) {
+  if (var == kDummyPreParserLexicalVariable || var == kDummyPreParserVariable) {
+    return true;
+  }
   DCHECK(var->location() != VariableLocation::MODULE);
   // Give var a read/write use if there is a chance it might be accessed
   // via an eval() call.  This is only possible if the variable has a
@@ -1823,7 +2045,10 @@
   if (has_forced_context_allocation()) return true;
   if (var->mode() == TEMPORARY) return false;
   if (is_catch_scope()) return true;
-  if (is_script_scope() && IsLexicalVariableMode(var->mode())) return true;
+  if ((is_script_scope() || is_eval_scope()) &&
+      IsLexicalVariableMode(var->mode())) {
+    return true;
+  }
   return var->has_forced_context_allocation() || inner_scope_calls_eval_;
 }
 
@@ -1880,6 +2105,7 @@
     DCHECK_EQ(this, var->scope());
     if (uses_sloppy_arguments) {
       var->set_is_used();
+      var->set_maybe_assigned();
       var->ForceContextAllocation();
     }
     AllocateParameter(var, i);
@@ -1946,9 +2172,8 @@
     new_target_ = nullptr;
   }
 
-  if (this_function_ != nullptr && !MustAllocate(this_function_)) {
-    this_function_ = nullptr;
-  }
+  NullifyRareVariableIf(RareVariable::kThisFunction,
+                        [=](Variable* var) { return !MustAllocate(var); });
 }
 
 void ModuleScope::AllocateModuleVariables() {
@@ -1967,9 +2192,10 @@
 
 void Scope::AllocateVariablesRecursively() {
   DCHECK(!already_resolved_);
-  DCHECK_EQ(0, num_stack_slots_);
+  DCHECK_IMPLIES(!FLAG_preparser_scope_analysis, num_stack_slots_ == 0);
+
   // Don't allocate variables of preparsed scopes.
-  if (is_declaration_scope() && AsDeclarationScope()->is_lazily_parsed()) {
+  if (is_declaration_scope() && AsDeclarationScope()->was_lazily_parsed()) {
     return;
   }
 
@@ -1994,9 +2220,9 @@
   // Force allocation of a context for this scope if necessary. For a 'with'
   // scope and for a function scope that makes an 'eval' call we need a context,
   // even if no local variables were statically allocated in the scope.
-  // Likewise for modules.
+  // Likewise for modules and function scopes representing asm.js modules.
   bool must_have_context =
-      is_with_scope() || is_module_scope() ||
+      is_with_scope() || is_module_scope() || IsAsmModule() ||
       (is_function_scope() && calls_sloppy_eval()) ||
       (is_block_scope() && is_declaration_scope() && calls_sloppy_eval());
 
@@ -2043,6 +2269,17 @@
   }
 }
 
+void Scope::CollectVariableData(PreParsedScopeData* data) {
+  PreParsedScopeData::ScopeScope scope_scope(data, scope_type(),
+                                             start_position(), end_position());
+  for (Variable* local : locals_) {
+    scope_scope.MaybeAddVariable(local);
+  }
+  for (Scope* inner = inner_scope_; inner != nullptr; inner = inner->sibling_) {
+    inner->CollectVariableData(data);
+  }
+}
+
 int Scope::StackLocalCount() const {
   Variable* function =
       is_function_scope() ? AsDeclarationScope()->function_var() : nullptr;
diff --git a/src/ast/scopes.h b/src/ast/scopes.h
index c7d88ac..119d77c 100644
--- a/src/ast/scopes.h
+++ b/src/ast/scopes.h
@@ -19,7 +19,9 @@
 class AstRawString;
 class Declaration;
 class ParseInfo;
+class PreParsedScopeData;
 class SloppyBlockFunctionStatement;
+class Statement;
 class StringSet;
 class VariableProxy;
 
@@ -28,11 +30,17 @@
  public:
   explicit VariableMap(Zone* zone);
 
-  Variable* Declare(Zone* zone, Scope* scope, const AstRawString* name,
-                    VariableMode mode, VariableKind kind,
-                    InitializationFlag initialization_flag,
-                    MaybeAssignedFlag maybe_assigned_flag = kNotAssigned,
-                    bool* added = nullptr);
+  Variable* Declare(
+      Zone* zone, Scope* scope, const AstRawString* name, VariableMode mode,
+      VariableKind kind = NORMAL_VARIABLE,
+      InitializationFlag initialization_flag = kCreatedInitialized,
+      MaybeAssignedFlag maybe_assigned_flag = kNotAssigned,
+      bool* added = nullptr);
+
+  // Records that "name" exists (if not recorded yet) but doesn't create a
+  // Variable. Useful for preparsing.
+  Variable* DeclareName(Zone* zone, const AstRawString* name,
+                        VariableMode mode);
 
   Variable* Lookup(const AstRawString* name);
   void Remove(Variable* var);
@@ -43,9 +51,24 @@
 // Sloppy block-scoped function declarations to var-bind
 class SloppyBlockFunctionMap : public ZoneHashMap {
  public:
+  class Delegate : public ZoneObject {
+   public:
+    explicit Delegate(Scope* scope,
+                      SloppyBlockFunctionStatement* statement = nullptr)
+        : scope_(scope), statement_(statement), next_(nullptr) {}
+    void set_statement(Statement* statement);
+    void set_next(Delegate* next) { next_ = next; }
+    Delegate* next() const { return next_; }
+    Scope* scope() const { return scope_; }
+
+   private:
+    Scope* scope_;
+    SloppyBlockFunctionStatement* statement_;
+    Delegate* next_;
+  };
+
   explicit SloppyBlockFunctionMap(Zone* zone);
-  void Declare(Zone* zone, const AstRawString* name,
-               SloppyBlockFunctionStatement* statement);
+  void Declare(Zone* zone, const AstRawString* name, Delegate* delegate);
 };
 
 enum class AnalyzeMode { kRegular, kDebugger };
@@ -148,7 +171,8 @@
   // Declare a local variable in this scope. If the variable has been
   // declared before, the previously declared variable is returned.
   Variable* DeclareLocal(const AstRawString* name, VariableMode mode,
-                         InitializationFlag init_flag, VariableKind kind,
+                         InitializationFlag init_flag = kCreatedInitialized,
+                         VariableKind kind = NORMAL_VARIABLE,
                          MaybeAssignedFlag maybe_assigned_flag = kNotAssigned);
 
   Variable* DeclareVariable(Declaration* declaration, VariableMode mode,
@@ -157,6 +181,9 @@
                             bool* sloppy_mode_block_scope_function_redefinition,
                             bool* ok);
 
+  // The return value is meaningful only if FLAG_preparser_scope_analysis is on.
+  Variable* DeclareVariableName(const AstRawString* name, VariableMode mode);
+
   // Declarations list.
   ThreadedList<Declaration>* declarations() { return &decls_; }
 
@@ -177,7 +204,6 @@
   // allocated globally as a "ghost" variable. RemoveUnresolved removes
   // such a variable again if it was added; otherwise this is a no-op.
   bool RemoveUnresolved(VariableProxy* var);
-  bool RemoveUnresolved(const AstRawString* name);
 
   // Creates a new temporary variable in this scope's TemporaryScope.  The
   // name is only used for printing and cannot be used to find the variable.
@@ -207,14 +233,11 @@
   // Scope-specific info.
 
   // Inform the scope and outer scopes that the corresponding code contains an
-  // eval call. We don't record eval calls from innner scopes in the outer most
-  // script scope, as we only see those when parsing eagerly. If we recorded the
-  // calls then, the outer most script scope would look different depending on
-  // whether we parsed eagerly or not which is undesirable.
+  // eval call.
   void RecordEvalCall() {
     scope_calls_eval_ = true;
     inner_scope_calls_eval_ = true;
-    for (Scope* scope = outer_scope(); scope && !scope->is_script_scope();
+    for (Scope* scope = outer_scope(); scope != nullptr;
          scope = scope->outer_scope()) {
       scope->inner_scope_calls_eval_ = true;
     }
@@ -303,6 +326,7 @@
   bool calls_sloppy_eval() const {
     return scope_calls_eval_ && is_sloppy(language_mode());
   }
+  bool inner_scope_calls_eval() const { return inner_scope_calls_eval_; }
   bool IsAsmModule() const;
   bool IsAsmFunction() const;
   // Does this scope have the potential to execute declarations non-linearly?
@@ -387,7 +411,7 @@
   Scope* GetOuterScopeWithContext();
 
   // Analyze() must have been called once to create the ScopeInfo.
-  Handle<ScopeInfo> scope_info() {
+  Handle<ScopeInfo> scope_info() const {
     DCHECK(!scope_info_.is_null());
     return scope_info_;
   }
@@ -423,6 +447,22 @@
   void set_is_debug_evaluate_scope() { is_debug_evaluate_scope_ = true; }
   bool is_debug_evaluate_scope() const { return is_debug_evaluate_scope_; }
 
+  bool RemoveInnerScope(Scope* inner_scope) {
+    DCHECK_NOT_NULL(inner_scope);
+    if (inner_scope == inner_scope_) {
+      inner_scope_ = inner_scope_->sibling_;
+      return true;
+    }
+    for (Scope* scope = inner_scope_; scope != nullptr;
+         scope = scope->sibling_) {
+      if (scope->sibling_ == inner_scope) {
+        scope->sibling_ = scope->sibling_->sibling_;
+        return true;
+      }
+    }
+    return false;
+  }
+
  protected:
   explicit Scope(Zone* zone);
 
@@ -431,10 +471,11 @@
   }
 
  private:
-  Variable* Declare(Zone* zone, Scope* scope, const AstRawString* name,
-                    VariableMode mode, VariableKind kind,
-                    InitializationFlag initialization_flag,
-                    MaybeAssignedFlag maybe_assigned_flag = kNotAssigned);
+  Variable* Declare(
+      Zone* zone, const AstRawString* name, VariableMode mode,
+      VariableKind kind = NORMAL_VARIABLE,
+      InitializationFlag initialization_flag = kCreatedInitialized,
+      MaybeAssignedFlag maybe_assigned_flag = kNotAssigned);
 
   // This method should only be invoked on scopes created during parsing (i.e.,
   // not deserialized from a context). Also, since NeedsContext() is only
@@ -442,6 +483,8 @@
   // should also be invoked after resolution.
   bool NeedsScopeInfo() const;
 
+  Variable* NewTemporary(const AstRawString* name,
+                         MaybeAssignedFlag maybe_assigned);
   Zone* zone_;
 
   // Scope tree.
@@ -527,7 +570,6 @@
   // list along the way, so full resolution cannot be done afterwards.
   // If a ParseInfo* is passed, non-free variables will be resolved.
   VariableProxy* FetchFreeVariables(DeclarationScope* max_outer_scope,
-                                    bool try_to_resolve = true,
                                     ParseInfo* info = nullptr,
                                     VariableProxy* stack = nullptr);
 
@@ -548,6 +590,8 @@
   void AllocateDebuggerScopeInfos(Isolate* isolate,
                                   MaybeHandle<ScopeInfo> outer_scope);
 
+  void CollectVariableData(PreParsedScopeData* data);
+
   // Construct a scope based on the scope info.
   Scope(Zone* zone, ScopeType type, Handle<ScopeInfo> scope_info);
 
@@ -556,33 +600,18 @@
         Handle<ScopeInfo> scope_info);
 
   void AddInnerScope(Scope* inner_scope) {
-    DCHECK_EQ(!needs_migration_, inner_scope->zone() == zone());
     inner_scope->sibling_ = inner_scope_;
     inner_scope_ = inner_scope;
     inner_scope->outer_scope_ = this;
   }
 
-  void RemoveInnerScope(Scope* inner_scope) {
-    DCHECK_NOT_NULL(inner_scope);
-    if (inner_scope == inner_scope_) {
-      inner_scope_ = inner_scope_->sibling_;
-      return;
-    }
-    for (Scope* scope = inner_scope_; scope != nullptr;
-         scope = scope->sibling_) {
-      if (scope->sibling_ == inner_scope) {
-        scope->sibling_ = scope->sibling_->sibling_;
-        return;
-      }
-    }
-  }
-
   void SetDefaults();
 
   friend class DeclarationScope;
+  friend class ScopeTestHelper;
 };
 
-class DeclarationScope : public Scope {
+class V8_EXPORT_PRIVATE DeclarationScope : public Scope {
  public:
   DeclarationScope(Zone* zone, Scope* outer_scope, ScopeType scope_type,
                    FunctionKind function_kind = kNormalFunction);
@@ -616,7 +645,15 @@
                                         IsClassConstructor(function_kind())));
   }
 
-  bool is_lazily_parsed() const { return is_lazily_parsed_; }
+  bool was_lazily_parsed() const { return was_lazily_parsed_; }
+
+#ifdef DEBUG
+  void set_is_being_lazily_parsed(bool is_being_lazily_parsed) {
+    is_being_lazily_parsed_ = is_being_lazily_parsed;
+  }
+  bool is_being_lazily_parsed() const { return is_being_lazily_parsed_; }
+#endif
+
   bool ShouldEagerCompile() const;
   void set_should_eager_compile();
 
@@ -629,7 +666,7 @@
   bool asm_module() const { return asm_module_; }
   void set_asm_module();
   bool asm_function() const { return asm_function_; }
-  void set_asm_function() { asm_module_ = true; }
+  void set_asm_function() { asm_function_ = true; }
 
   void DeclareThis(AstValueFactory* ast_value_factory);
   void DeclareArguments(AstValueFactory* ast_value_factory);
@@ -645,6 +682,11 @@
   // calls sloppy eval.
   Variable* DeclareFunctionVar(const AstRawString* name);
 
+  // Declare some special internal variables which must be accessible to
+  // Ignition without ScopeInfo.
+  Variable* DeclareGeneratorObjectVar(const AstRawString* name);
+  Variable* DeclarePromiseVar(const AstRawString* name);
+
   // Declare a parameter in this scope.  When there are duplicated
   // parameters the rightmost one 'wins'.  However, the implementation
   // expects all parameters to be declared and from left to right.
@@ -652,6 +694,11 @@
                              bool is_optional, bool is_rest, bool* is_duplicate,
                              AstValueFactory* ast_value_factory);
 
+  // Declares that a parameter with the name exists. Creates a Variable and
+  // returns it if FLAG_preparser_scope_analysis is on.
+  Variable* DeclareParameterName(const AstRawString* name, bool is_rest,
+                                 AstValueFactory* ast_value_factory);
+
   // Declare an implicit global variable in this scope which must be a
   // script scope.  The variable was introduced (possibly from an inner
   // scope) by a reference to an unresolved variable with no intervening
@@ -683,6 +730,17 @@
     return function_;
   }
 
+  Variable* generator_object_var() const {
+    DCHECK(is_function_scope() || is_module_scope());
+    return GetRareVariable(RareVariable::kGeneratorObject);
+  }
+
+  Variable* promise_var() const {
+    DCHECK(is_function_scope());
+    DCHECK(IsAsyncFunction(function_kind_));
+    return GetRareVariable(RareVariable::kPromise);
+  }
+
   // Parameters. The left-most parameter has index 0.
   // Only valid for function and module scopes.
   Variable* parameter(int index) const {
@@ -723,12 +781,14 @@
   }
 
   Variable* this_function_var() const {
+    Variable* this_function = GetRareVariable(RareVariable::kThisFunction);
+
     // This is only used in derived constructors atm.
-    DCHECK(this_function_ == nullptr ||
+    DCHECK(this_function == nullptr ||
            (is_function_scope() && (IsClassConstructor(function_kind()) ||
                                     IsConciseMethod(function_kind()) ||
                                     IsAccessorFunction(function_kind()))));
-    return this_function_;
+    return this_function;
   }
 
   // Adds a local variable in this scope's locals list. This is for adjusting
@@ -736,10 +796,9 @@
   // initializers.
   void AddLocal(Variable* var);
 
-  void DeclareSloppyBlockFunction(const AstRawString* name,
-                                  SloppyBlockFunctionStatement* statement) {
-    sloppy_block_function_map_.Declare(zone(), name, statement);
-  }
+  void DeclareSloppyBlockFunction(
+      const AstRawString* name, Scope* scope,
+      SloppyBlockFunctionStatement* statement = nullptr);
 
   // Go through sloppy_block_function_map_ and hoist those (into this scope)
   // which should be hoisted.
@@ -759,7 +818,8 @@
   // records variables which cannot be resolved inside the Scope (we don't yet
   // know what they will resolve to since the outer Scopes are incomplete) and
   // migrates them into migrate_to.
-  void AnalyzePartially(AstNodeFactory* ast_node_factory);
+  void AnalyzePartially(AstNodeFactory* ast_node_factory,
+                        PreParsedScopeData* preparsed_scope_data);
 
   Handle<StringSet> CollectNonLocals(ParseInfo* info,
                                      Handle<StringSet> non_locals);
@@ -819,7 +879,11 @@
   // This scope uses "super" property ('super.foo').
   bool scope_uses_super_property_ : 1;
   bool should_eager_compile_ : 1;
-  bool is_lazily_parsed_ : 1;
+  // Set to true after we have finished lazy parsing the scope.
+  bool was_lazily_parsed_ : 1;
+#if DEBUG
+  bool is_being_lazily_parsed_ : 1;
+#endif
 
   // Parameter list in source order.
   ZoneList<Variable*> params_;
@@ -833,8 +897,48 @@
   Variable* new_target_;
   // Convenience variable; function scopes only.
   Variable* arguments_;
-  // Convenience variable; Subclass constructor only
-  Variable* this_function_;
+
+  struct RareData : public ZoneObject {
+    // Convenience variable; Subclass constructor only
+    Variable* this_function = nullptr;
+
+    // Generator object, if any; generator function scopes and module scopes
+    // only.
+    Variable* generator_object = nullptr;
+    // Promise, if any; async function scopes only.
+    Variable* promise = nullptr;
+  };
+
+  enum class RareVariable {
+    kThisFunction = offsetof(RareData, this_function),
+    kGeneratorObject = offsetof(RareData, generator_object),
+    kPromise = offsetof(RareData, promise)
+  };
+
+  V8_INLINE RareData* EnsureRareData() {
+    if (rare_data_ == nullptr) {
+      rare_data_ = new (zone_) RareData;
+    }
+    return rare_data_;
+  }
+
+  V8_INLINE Variable* GetRareVariable(RareVariable id) const {
+    if (rare_data_ == nullptr) return nullptr;
+    return *reinterpret_cast<Variable**>(
+        reinterpret_cast<uint8_t*>(rare_data_) + static_cast<ptrdiff_t>(id));
+  }
+
+  // Set `var` to null if it's non-null and Predicate (Variable*) -> bool
+  // returns true.
+  template <typename Predicate>
+  V8_INLINE void NullifyRareVariableIf(RareVariable id, Predicate predicate) {
+    if (V8_LIKELY(rare_data_ == nullptr)) return;
+    Variable** var = reinterpret_cast<Variable**>(
+        reinterpret_cast<uint8_t*>(rare_data_) + static_cast<ptrdiff_t>(id));
+    if (*var && predicate(*var)) *var = nullptr;
+  }
+
+  RareData* rare_data_ = nullptr;
 };
 
 class ModuleScope final : public DeclarationScope {
diff --git a/src/ast/variables.cc b/src/ast/variables.cc
index 3771bfe..cd1d8f7 100644
--- a/src/ast/variables.cc
+++ b/src/ast/variables.cc
@@ -6,6 +6,7 @@
 
 #include "src/ast/scopes.h"
 #include "src/globals.h"
+#include "src/objects-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -36,9 +37,8 @@
 bool Variable::IsGlobalObjectProperty() const {
   // Temporaries are never global, they must always be allocated in the
   // activation frame.
-  return (IsDynamicVariableMode(mode()) ||
-          (IsDeclaredVariableMode(mode()) && !IsLexicalVariableMode(mode()))) &&
-         scope_ != NULL && scope_->is_script_scope();
+  return (IsDynamicVariableMode(mode()) || mode() == VAR) &&
+         scope_ != nullptr && scope_->is_script_scope();
 }
 
 }  // namespace internal