Merge V8 5.3.332.45.  DO NOT MERGE

Test: Manual

FPIIM-449

Change-Id: Id3254828b068abdea3cb10442e0172a8c9a98e03
(cherry picked from commit 13e2dadd00298019ed862f2b2fc5068bba730bcf)
diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc
index da8b626..d8d60f3 100644
--- a/src/compiler/ast-graph-builder.cc
+++ b/src/compiler/ast-graph-builder.cc
@@ -281,9 +281,9 @@
     return NewPathToken(TokenDispenserForFinally::kFallThroughToken);
   }
   Node* NewPathDispatchCondition(Node* t1, Node* t2) {
-    // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi
-    // nodes all have kRepTagged|kTypeAny, which causes representation mismatch.
-    return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2);
+    return owner_->NewNode(
+        owner_->javascript()->StrictEqual(CompareOperationHints::Any()), t1,
+        t2);
   }
 
  private:
@@ -416,8 +416,15 @@
   FrameStateBeforeAndAfter(AstGraphBuilder* builder, BailoutId id_before)
       : builder_(builder), frame_state_before_(nullptr) {
     frame_state_before_ = id_before == BailoutId::None()
-                              ? builder_->jsgraph()->EmptyFrameState()
+                              ? builder_->GetEmptyFrameState()
                               : builder_->environment()->Checkpoint(id_before);
+    if (id_before != BailoutId::None()) {
+      // Create an explicit checkpoint node for before the operation.
+      Node* node = builder_->NewNode(builder_->common()->Checkpoint());
+      DCHECK_EQ(IrOpcode::kDead,
+                NodeProperties::GetFrameStateInput(node, 0)->opcode());
+      NodeProperties::ReplaceFrameStateInput(node, 0, frame_state_before_);
+    }
   }
 
   void AddToNode(
@@ -435,7 +442,7 @@
 
       Node* frame_state_after =
           id_after == BailoutId::None()
-              ? builder_->jsgraph()->EmptyFrameState()
+              ? builder_->GetEmptyFrameState()
               : builder_->environment()->Checkpoint(id_after, combine,
                                                     node_has_exception);
 
@@ -444,6 +451,7 @@
 
     if (count >= 2) {
       // Add the frame state for before the operation.
+      // TODO(mstarzinger): Get rid of frame state input before!
       DCHECK_EQ(IrOpcode::kDead,
                 NodeProperties::GetFrameStateInput(node, 1)->opcode());
       NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before_);
@@ -539,6 +547,18 @@
   return new_target_.get();
 }
 
+Node* AstGraphBuilder::GetEmptyFrameState() {
+  if (!empty_frame_state_.is_set()) {
+    const Operator* op = common()->FrameState(
+        BailoutId::None(), OutputFrameStateCombine::Ignore(), nullptr);
+    Node* node = graph()->NewNode(
+        op, jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(),
+        jsgraph()->EmptyStateValues(), jsgraph()->NoContextConstant(),
+        jsgraph()->UndefinedConstant(), graph()->start());
+    empty_frame_state_.set(node);
+  }
+  return empty_frame_state_.get();
+}
 
 bool AstGraphBuilder::CreateGraph(bool stack_check) {
   Scope* scope = info()->scope();
@@ -875,7 +895,7 @@
                                                OutputFrameStateCombine combine,
                                                bool owner_has_exception) {
   if (!builder()->info()->is_deoptimization_enabled()) {
-    return builder()->jsgraph()->EmptyFrameState();
+    return builder()->GetEmptyFrameState();
   }
 
   UpdateStateValues(&parameters_node_, 0, parameters_count());
@@ -1112,18 +1132,10 @@
       }
       break;
     case VariableLocation::LOOKUP: {
+      DCHECK(!hole_init);
       Node* name = jsgraph()->Constant(variable->name());
-      // For variables we must not push an initial value (such as 'undefined')
-      // because we may have a (legal) redeclaration and we must not destroy
-      // the current value.
-      Node* value =
-          hole_init ? jsgraph()->TheHoleConstant()
-                    : jsgraph()->ZeroConstant();  // Indicates no initial value.
-      Node* attr =
-          jsgraph()->Constant(variable->DeclarationPropertyAttributes());
-      const Operator* op =
-          javascript()->CallRuntime(Runtime::kDeclareLookupSlot);
-      Node* store = NewNode(op, name, value, attr);
+      const Operator* op = javascript()->CallRuntime(Runtime::kDeclareEvalVar);
+      Node* store = NewNode(op, name);
       PrepareFrameState(store, decl->proxy()->id());
       break;
     }
@@ -1162,11 +1174,9 @@
       VisitForValue(decl->fun());
       Node* value = environment()->Pop();
       Node* name = jsgraph()->Constant(variable->name());
-      Node* attr =
-          jsgraph()->Constant(variable->DeclarationPropertyAttributes());
       const Operator* op =
-          javascript()->CallRuntime(Runtime::kDeclareLookupSlot);
-      Node* store = NewNode(op, name, value, attr);
+          javascript()->CallRuntime(Runtime::kDeclareEvalFunction);
+      Node* store = NewNode(op, name, value);
       PrepareFrameState(store, decl->proxy()->id());
       break;
     }
@@ -1289,7 +1299,15 @@
     VisitForValue(clause->label());
     Node* label = environment()->Pop();
     Node* tag = environment()->Top();
-    const Operator* op = javascript()->StrictEqual();
+
+    CompareOperationHints hints;
+    if (!type_hint_analysis_ ||
+        !type_hint_analysis_->GetCompareOperationHints(clause->CompareId(),
+                                                       &hints)) {
+      hints = CompareOperationHints::Any();
+    }
+
+    const Operator* op = javascript()->StrictEqual(hints);
     Node* condition = NewNode(op, tag, label);
     compare_switch.BeginLabel(i, condition);
 
@@ -1365,10 +1383,12 @@
   for_block.BeginBlock();
   // Check for null or undefined before entering loop.
   Node* is_null_cond =
-      NewNode(javascript()->StrictEqual(), object, jsgraph()->NullConstant());
+      NewNode(javascript()->StrictEqual(CompareOperationHints::Any()), object,
+              jsgraph()->NullConstant());
   for_block.BreakWhen(is_null_cond, BranchHint::kFalse);
-  Node* is_undefined_cond = NewNode(javascript()->StrictEqual(), object,
-                                    jsgraph()->UndefinedConstant());
+  Node* is_undefined_cond =
+      NewNode(javascript()->StrictEqual(CompareOperationHints::Any()), object,
+              jsgraph()->UndefinedConstant());
   for_block.BreakWhen(is_undefined_cond, BranchHint::kFalse);
   {
     // Convert object to jsobject.
@@ -1411,8 +1431,9 @@
       PrepareFrameState(value, stmt->FilterId(),
                         OutputFrameStateCombine::Push());
       IfBuilder test_value(this);
-      Node* test_value_cond = NewNode(javascript()->StrictEqual(), value,
-                                      jsgraph()->UndefinedConstant());
+      Node* test_value_cond =
+          NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
+                  value, jsgraph()->UndefinedConstant());
       test_value.If(test_value_cond, BranchHint::kFalse);
       test_value.Then();
       test_value.Else();
@@ -1602,12 +1623,12 @@
   environment()->Push(literal);
 
   // Load the "prototype" from the constructor.
-  FrameStateBeforeAndAfter states(this, expr->CreateLiteralId());
+  PrepareEagerCheckpoint(expr->CreateLiteralId());
   Handle<Name> name = isolate()->factory()->prototype_string();
   VectorSlotPair pair = CreateVectorSlotPair(expr->PrototypeSlot());
   Node* prototype = BuildNamedLoad(literal, name, pair);
-  states.AddToNode(prototype, expr->PrototypeId(),
-                   OutputFrameStateCombine::Push());
+  PrepareFrameState(prototype, expr->PrototypeId(),
+                    OutputFrameStateCombine::Push());
   environment()->Push(prototype);
 
   // Create nodes to store method values into the literal.
@@ -1647,7 +1668,8 @@
             jsgraph()->Constant(property->NeedsSetFunctionName());
         const Operator* op =
             javascript()->CallRuntime(Runtime::kDefineDataPropertyInLiteral);
-        NewNode(op, receiver, key, value, attr, set_function_name);
+        Node* call = NewNode(op, receiver, key, value, attr, set_function_name);
+        PrepareFrameState(call, BailoutId::None());
         break;
       }
       case ObjectLiteral::Property::GETTER: {
@@ -1676,12 +1698,11 @@
   // Assign to class variable.
   if (expr->class_variable_proxy() != nullptr) {
     Variable* var = expr->class_variable_proxy()->var();
-    FrameStateBeforeAndAfter states(this, BailoutId::None());
     VectorSlotPair feedback = CreateVectorSlotPair(
         expr->NeedsProxySlot() ? expr->ProxySlot()
                                : FeedbackVectorSlot::Invalid());
     BuildVariableAssignment(var, literal, Token::INIT, feedback,
-                            BailoutId::None(), states);
+                            BailoutId::None());
   }
   ast_context()->ProduceValue(literal);
 }
@@ -1715,8 +1736,8 @@
 
 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
   VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot());
-  FrameStateBeforeAndAfter states(this, BeforeId(expr));
-  Node* value = BuildVariableLoad(expr->var(), expr->id(), states, pair,
+  PrepareEagerCheckpoint(BeforeId(expr));
+  Node* value = BuildVariableLoad(expr->var(), expr->id(), pair,
                                   ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
 }
@@ -1776,15 +1797,15 @@
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForValue(property->value());
-            FrameStateBeforeAndAfter states(this, property->value()->id());
+            PrepareEagerCheckpoint(property->value()->id());
             Node* value = environment()->Pop();
             Node* literal = environment()->Top();
             Handle<Name> name = key->AsPropertyName();
             VectorSlotPair feedback =
                 CreateVectorSlotPair(property->GetSlot(0));
             Node* store = BuildNamedStore(literal, name, value, feedback);
-            states.AddToNode(store, key->id(),
-                             OutputFrameStateCombine::Ignore());
+            PrepareFrameState(store, key->id(),
+                              OutputFrameStateCombine::Ignore());
             BuildSetHomeObject(value, literal, property, 1);
           } else {
             VisitForEffect(property->value());
@@ -1823,12 +1844,16 @@
       }
       case ObjectLiteral::Property::GETTER:
         if (property->emit_store()) {
-          accessor_table.lookup(key)->second->getter = property;
+          AccessorTable::Iterator it = accessor_table.lookup(key);
+          it->second->bailout_id = expr->GetIdForPropertySet(property_index);
+          it->second->getter = property;
         }
         break;
       case ObjectLiteral::Property::SETTER:
         if (property->emit_store()) {
-          accessor_table.lookup(key)->second->setter = property;
+          AccessorTable::Iterator it = accessor_table.lookup(key);
+          it->second->bailout_id = expr->GetIdForPropertySet(property_index);
+          it->second->setter = property;
         }
         break;
     }
@@ -1849,8 +1874,7 @@
     const Operator* op =
         javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked);
     Node* call = NewNode(op, literal, name, getter, setter, attr);
-    // This should not lazy deopt on a new literal.
-    PrepareFrameState(call, BailoutId::None());
+    PrepareFrameState(call, it->second->bailout_id);
   }
 
   // Object literals have two parts. The "static" part on the left contains no
@@ -1896,7 +1920,8 @@
             jsgraph()->Constant(property->NeedsSetFunctionName());
         const Operator* op =
             javascript()->CallRuntime(Runtime::kDefineDataPropertyInLiteral);
-        NewNode(op, receiver, key, value, attr, set_function_name);
+        Node* call = NewNode(op, receiver, key, value, attr, set_function_name);
+        PrepareFrameState(call, expr->GetIdForPropertySet(property_index));
         break;
       }
       case ObjectLiteral::Property::PROTOTYPE:
@@ -1961,14 +1986,14 @@
 
     VisitForValue(subexpr);
     {
-      FrameStateBeforeAndAfter states(this, subexpr->id());
+      PrepareEagerCheckpoint(subexpr->id());
       VectorSlotPair pair = CreateVectorSlotPair(expr->LiteralFeedbackSlot());
       Node* value = environment()->Pop();
       Node* index = jsgraph()->Constant(array_index);
       Node* literal = environment()->Top();
       Node* store = BuildKeyedStore(literal, index, value, pair);
-      states.AddToNode(store, expr->GetIdForElement(array_index),
-                       OutputFrameStateCombine::Ignore());
+      PrepareFrameState(store, expr->GetIdForElement(array_index),
+                        OutputFrameStateCombine::Ignore());
     }
   }
 
@@ -2011,49 +2036,49 @@
     case VARIABLE: {
       Variable* var = expr->AsVariableProxy()->var();
       environment()->Push(value);
-      FrameStateBeforeAndAfter states(this, bailout_id_before);
+      PrepareEagerCheckpoint(bailout_id_before);
       value = environment()->Pop();
       BuildVariableAssignment(var, value, Token::ASSIGN, feedback,
-                              bailout_id_after, states);
+                              bailout_id_after);
       break;
     }
     case NAMED_PROPERTY: {
       environment()->Push(value);
       VisitForValue(property->obj());
-      FrameStateBeforeAndAfter states(this, property->obj()->id());
+      PrepareEagerCheckpoint(property->obj()->id());
       Node* object = environment()->Pop();
       value = environment()->Pop();
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       Node* store = BuildNamedStore(object, name, value, feedback);
-      states.AddToNode(store, bailout_id_after,
-                       OutputFrameStateCombine::Ignore());
+      PrepareFrameState(store, bailout_id_after,
+                        OutputFrameStateCombine::Ignore());
       break;
     }
     case KEYED_PROPERTY: {
       environment()->Push(value);
       VisitForValue(property->obj());
       VisitForValue(property->key());
-      FrameStateBeforeAndAfter states(this, property->key()->id());
+      PrepareEagerCheckpoint(property->key()->id());
       Node* key = environment()->Pop();
       Node* object = environment()->Pop();
       value = environment()->Pop();
       Node* store = BuildKeyedStore(object, key, value, feedback);
-      states.AddToNode(store, bailout_id_after,
-                       OutputFrameStateCombine::Ignore());
+      PrepareFrameState(store, bailout_id_after,
+                        OutputFrameStateCombine::Ignore());
       break;
     }
     case NAMED_SUPER_PROPERTY: {
       environment()->Push(value);
       VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
       VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
-      FrameStateBeforeAndAfter states(this, property->obj()->id());
+      PrepareEagerCheckpoint(property->obj()->id());
       Node* home_object = environment()->Pop();
       Node* receiver = environment()->Pop();
       value = environment()->Pop();
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       Node* store = BuildNamedSuperStore(receiver, home_object, name, value);
-      states.AddToNode(store, bailout_id_after,
-                       OutputFrameStateCombine::Ignore());
+      PrepareFrameState(store, bailout_id_after,
+                        OutputFrameStateCombine::Ignore());
       break;
     }
     case KEYED_SUPER_PROPERTY: {
@@ -2061,14 +2086,14 @@
       VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
       VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
       VisitForValue(property->key());
-      FrameStateBeforeAndAfter states(this, property->key()->id());
+      PrepareEagerCheckpoint(property->key()->id());
       Node* key = environment()->Pop();
       Node* home_object = environment()->Pop();
       Node* receiver = environment()->Pop();
       value = environment()->Pop();
       Node* store = BuildKeyedSuperStore(receiver, home_object, key, value);
-      states.AddToNode(store, bailout_id_after,
-                       OutputFrameStateCombine::Ignore());
+      PrepareFrameState(store, bailout_id_after,
+                        OutputFrameStateCombine::Ignore());
       break;
     }
   }
@@ -2122,10 +2147,9 @@
         VariableProxy* proxy = expr->target()->AsVariableProxy();
         VectorSlotPair pair =
             CreateVectorSlotPair(proxy->VariableFeedbackSlot());
-        FrameStateBeforeAndAfter states(this, BeforeId(proxy));
-        old_value =
-            BuildVariableLoad(proxy->var(), expr->target()->id(), states, pair,
-                              OutputFrameStateCombine::Push());
+        PrepareEagerCheckpoint(BeforeId(proxy));
+        old_value = BuildVariableLoad(proxy->var(), expr->target()->id(), pair,
+                                      OutputFrameStateCombine::Push());
         break;
       }
       case NAMED_PROPERTY: {
@@ -2133,10 +2157,10 @@
         Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
         VectorSlotPair pair =
             CreateVectorSlotPair(property->PropertyFeedbackSlot());
-        FrameStateBeforeAndAfter states(this, property->obj()->id());
+        PrepareEagerCheckpoint(property->obj()->id());
         old_value = BuildNamedLoad(object, name, pair);
-        states.AddToNode(old_value, property->LoadId(),
-                         OutputFrameStateCombine::Push());
+        PrepareFrameState(old_value, property->LoadId(),
+                          OutputFrameStateCombine::Push());
         break;
       }
       case KEYED_PROPERTY: {
@@ -2144,10 +2168,10 @@
         Node* object = environment()->Peek(1);
         VectorSlotPair pair =
             CreateVectorSlotPair(property->PropertyFeedbackSlot());
-        FrameStateBeforeAndAfter states(this, property->key()->id());
+        PrepareEagerCheckpoint(property->key()->id());
         old_value = BuildKeyedLoad(object, key, pair);
-        states.AddToNode(old_value, property->LoadId(),
-                         OutputFrameStateCombine::Push());
+        PrepareFrameState(old_value, property->LoadId(),
+                          OutputFrameStateCombine::Push());
         break;
       }
       case NAMED_SUPER_PROPERTY: {
@@ -2156,10 +2180,10 @@
         Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
         VectorSlotPair pair =
             CreateVectorSlotPair(property->PropertyFeedbackSlot());
-        FrameStateBeforeAndAfter states(this, property->obj()->id());
+        PrepareEagerCheckpoint(property->obj()->id());
         old_value = BuildNamedSuperLoad(receiver, home_object, name, pair);
-        states.AddToNode(old_value, property->LoadId(),
-                         OutputFrameStateCombine::Push());
+        PrepareFrameState(old_value, property->LoadId(),
+                          OutputFrameStateCombine::Push());
         break;
       }
       case KEYED_SUPER_PROPERTY: {
@@ -2168,10 +2192,10 @@
         Node* receiver = environment()->Peek(2);
         VectorSlotPair pair =
             CreateVectorSlotPair(property->PropertyFeedbackSlot());
-        FrameStateBeforeAndAfter states(this, property->key()->id());
+        PrepareEagerCheckpoint(property->key()->id());
         old_value = BuildKeyedSuperLoad(receiver, home_object, key, pair);
-        states.AddToNode(old_value, property->LoadId(),
-                         OutputFrameStateCombine::Push());
+        PrepareFrameState(old_value, property->LoadId(),
+                          OutputFrameStateCombine::Push());
         break;
       }
     }
@@ -2199,31 +2223,29 @@
     }
   }
 
-  FrameStateBeforeAndAfter store_states(this, before_store_id);
   // Store the value.
+  PrepareEagerCheckpoint(before_store_id);
   Node* value = environment()->Pop();
   VectorSlotPair feedback = CreateVectorSlotPair(expr->AssignmentSlot());
   switch (assign_type) {
     case VARIABLE: {
       Variable* variable = expr->target()->AsVariableProxy()->var();
       BuildVariableAssignment(variable, value, expr->op(), feedback, expr->id(),
-                              store_states, ast_context()->GetStateCombine());
+                              ast_context()->GetStateCombine());
       break;
     }
     case NAMED_PROPERTY: {
       Node* object = environment()->Pop();
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       Node* store = BuildNamedStore(object, name, value, feedback);
-      store_states.AddToNode(store, expr->id(),
-                             ast_context()->GetStateCombine());
+      PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
       break;
     }
     case KEYED_PROPERTY: {
       Node* key = environment()->Pop();
       Node* object = environment()->Pop();
       Node* store = BuildKeyedStore(object, key, value, feedback);
-      store_states.AddToNode(store, expr->id(),
-                             ast_context()->GetStateCombine());
+      PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
       break;
     }
     case NAMED_SUPER_PROPERTY: {
@@ -2231,8 +2253,7 @@
       Node* receiver = environment()->Pop();
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       Node* store = BuildNamedSuperStore(receiver, home_object, name, value);
-      store_states.AddToNode(store, expr->id(),
-                             ast_context()->GetStateCombine());
+      PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
       break;
     }
     case KEYED_SUPER_PROPERTY: {
@@ -2240,8 +2261,7 @@
       Node* home_object = environment()->Pop();
       Node* receiver = environment()->Pop();
       Node* store = BuildKeyedSuperStore(receiver, home_object, key, value);
-      store_states.AddToNode(store, expr->id(),
-                             ast_context()->GetStateCombine());
+      PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
       break;
     }
   }
@@ -2275,44 +2295,44 @@
       break;
     case NAMED_PROPERTY: {
       VisitForValue(expr->obj());
-      FrameStateBeforeAndAfter states(this, expr->obj()->id());
+      PrepareEagerCheckpoint(expr->obj()->id());
       Node* object = environment()->Pop();
       Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName();
       value = BuildNamedLoad(object, name, pair);
-      states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
+      PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
       break;
     }
     case KEYED_PROPERTY: {
       VisitForValue(expr->obj());
       VisitForValue(expr->key());
-      FrameStateBeforeAndAfter states(this, expr->key()->id());
+      PrepareEagerCheckpoint(expr->key()->id());
       Node* key = environment()->Pop();
       Node* object = environment()->Pop();
       value = BuildKeyedLoad(object, key, pair);
-      states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
+      PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
       break;
     }
     case NAMED_SUPER_PROPERTY: {
       VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var());
       VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object());
-      FrameStateBeforeAndAfter states(this, expr->obj()->id());
+      PrepareEagerCheckpoint(expr->obj()->id());
       Node* home_object = environment()->Pop();
       Node* receiver = environment()->Pop();
       Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName();
       value = BuildNamedSuperLoad(receiver, home_object, name, pair);
-      states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
+      PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
       break;
     }
     case KEYED_SUPER_PROPERTY: {
       VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var());
       VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object());
       VisitForValue(expr->key());
-      FrameStateBeforeAndAfter states(this, expr->key()->id());
+      PrepareEagerCheckpoint(expr->key()->id());
       Node* key = environment()->Pop();
       Node* home_object = environment()->Pop();
       Node* receiver = environment()->Pop();
       value = BuildKeyedSuperLoad(receiver, home_object, key, pair);
-      states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
+      PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
       break;
     }
   }
@@ -2334,10 +2354,9 @@
     case Call::GLOBAL_CALL: {
       VariableProxy* proxy = callee->AsVariableProxy();
       VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
-      FrameStateBeforeAndAfter states(this, BeforeId(proxy));
-      callee_value =
-          BuildVariableLoad(proxy->var(), expr->expression()->id(), states,
-                            pair, OutputFrameStateCombine::Push());
+      PrepareEagerCheckpoint(BeforeId(proxy));
+      callee_value = BuildVariableLoad(proxy->var(), expr->expression()->id(),
+                                       pair, OutputFrameStateCombine::Push());
       receiver_hint = ConvertReceiverMode::kNullOrUndefined;
       receiver_value = jsgraph()->UndefinedConstant();
       break;
@@ -2360,12 +2379,12 @@
       VectorSlotPair feedback =
           CreateVectorSlotPair(property->PropertyFeedbackSlot());
       VisitForValue(property->obj());
-      FrameStateBeforeAndAfter states(this, property->obj()->id());
+      PrepareEagerCheckpoint(property->obj()->id());
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       Node* object = environment()->Top();
       callee_value = BuildNamedLoad(object, name, feedback);
-      states.AddToNode(callee_value, property->LoadId(),
-                       OutputFrameStateCombine::Push());
+      PrepareFrameState(callee_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       // Note that a property call requires the receiver to be wrapped into
       // an object for sloppy callees. However the receiver is guaranteed
       // not to be null or undefined at this point.
@@ -2379,12 +2398,12 @@
           CreateVectorSlotPair(property->PropertyFeedbackSlot());
       VisitForValue(property->obj());
       VisitForValue(property->key());
-      FrameStateBeforeAndAfter states(this, property->key()->id());
+      PrepareEagerCheckpoint(property->key()->id());
       Node* key = environment()->Pop();
       Node* object = environment()->Top();
       callee_value = BuildKeyedLoad(object, key, feedback);
-      states.AddToNode(callee_value, property->LoadId(),
-                       OutputFrameStateCombine::Push());
+      PrepareFrameState(callee_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       // Note that a property call requires the receiver to be wrapped into
       // an object for sloppy callees. However the receiver is guaranteed
       // not to be null or undefined at this point.
@@ -2401,10 +2420,10 @@
       Node* home = environment()->Peek(1);
       Node* object = environment()->Top();
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
-      FrameStateBeforeAndAfter states(this, property->obj()->id());
+      PrepareEagerCheckpoint(property->obj()->id());
       callee_value = BuildNamedSuperLoad(object, home, name, VectorSlotPair());
-      states.AddToNode(callee_value, property->LoadId(),
-                       OutputFrameStateCombine::Push());
+      PrepareFrameState(callee_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       // Note that a property call requires the receiver to be wrapped into
       // an object for sloppy callees. Since the receiver is not the target of
       // the load, it could very well be null or undefined at this point.
@@ -2424,10 +2443,10 @@
       Node* key = environment()->Pop();
       Node* home = environment()->Pop();
       Node* object = environment()->Pop();
-      FrameStateBeforeAndAfter states(this, property->key()->id());
+      PrepareEagerCheckpoint(property->key()->id());
       callee_value = BuildKeyedSuperLoad(object, home, key, VectorSlotPair());
-      states.AddToNode(callee_value, property->LoadId(),
-                       OutputFrameStateCombine::Push());
+      PrepareFrameState(callee_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       // Note that a property call requires the receiver to be wrapped into
       // an object for sloppy callees. Since the receiver is not the target of
       // the load, it could very well be null or undefined at this point.
@@ -2500,10 +2519,10 @@
   VectorSlotPair feedback = CreateVectorSlotPair(expr->CallFeedbackICSlot());
   const Operator* call = javascript()->CallFunction(
       args->length() + 2, feedback, receiver_hint, expr->tail_call_mode());
-  FrameStateBeforeAndAfter states(this, expr->CallId());
+  PrepareEagerCheckpoint(expr->CallId());
   Node* value = ProcessArguments(call, args->length() + 2);
   environment()->Push(value->InputAt(0));  // The callee passed to the call.
-  states.AddToNode(value, expr->ReturnId(), OutputFrameStateCombine::Push());
+  PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push());
   environment()->Drop(1);
   ast_context()->ProduceValue(value);
 }
@@ -2531,9 +2550,9 @@
   // Create node to perform the super call.
   const Operator* call =
       javascript()->CallConstruct(args->length() + 2, VectorSlotPair());
-  FrameStateBeforeAndAfter states(this, super->new_target_var()->id());
+  PrepareEagerCheckpoint(super->new_target_var()->id());
   Node* value = ProcessArguments(call, args->length() + 2);
-  states.AddToNode(value, expr->ReturnId(), OutputFrameStateCombine::Push());
+  PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push());
   ast_context()->ProduceValue(value);
 }
 
@@ -2547,8 +2566,8 @@
 
   // The baseline compiler doesn't push the new.target, so we need to record
   // the frame state before the push.
-  FrameStateBeforeAndAfter states(
-      this, args->is_empty() ? expr->expression()->id() : args->last()->id());
+  PrepareEagerCheckpoint(args->is_empty() ? expr->expression()->id()
+                                          : args->last()->id());
 
   // The new target is the same as the callee.
   environment()->Push(environment()->Peek(args->length()));
@@ -2558,7 +2577,7 @@
   const Operator* call =
       javascript()->CallConstruct(args->length() + 2, feedback);
   Node* value = ProcessArguments(call, args->length() + 2);
-  states.AddToNode(value, expr->ReturnId(), OutputFrameStateCombine::Push());
+  PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push());
   ast_context()->ProduceValue(value);
 }
 
@@ -2578,9 +2597,9 @@
 
   // Create node to perform the JS runtime call.
   const Operator* call = javascript()->CallFunction(args->length() + 2);
-  FrameStateBeforeAndAfter states(this, expr->CallId());
+  PrepareEagerCheckpoint(expr->CallId());
   Node* value = ProcessArguments(call, args->length() + 2);
-  states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
+  PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
 }
 
@@ -2599,9 +2618,9 @@
   // Create node to perform the runtime call.
   Runtime::FunctionId functionId = expr->function()->function_id;
   const Operator* call = javascript()->CallRuntime(functionId, args->length());
-  FrameStateBeforeAndAfter states(this, expr->CallId());
+  PrepareEagerCheckpoint(expr->CallId());
   Node* value = ProcessArguments(call, args->length());
-  states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
+  PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   ast_context()->ProduceValue(value);
 }
 
@@ -2642,52 +2661,51 @@
     case VARIABLE: {
       VariableProxy* proxy = expr->expression()->AsVariableProxy();
       VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
-      FrameStateBeforeAndAfter states(this, BeforeId(proxy));
-      old_value =
-          BuildVariableLoad(proxy->var(), expr->expression()->id(), states,
-                            pair, OutputFrameStateCombine::Push());
+      PrepareEagerCheckpoint(BeforeId(proxy));
+      old_value = BuildVariableLoad(proxy->var(), expr->expression()->id(),
+                                    pair, OutputFrameStateCombine::Push());
       stack_depth = 0;
       break;
     }
     case NAMED_PROPERTY: {
       VisitForValue(property->obj());
-      FrameStateBeforeAndAfter states(this, property->obj()->id());
+      PrepareEagerCheckpoint(property->obj()->id());
       Node* object = environment()->Top();
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       VectorSlotPair pair =
           CreateVectorSlotPair(property->PropertyFeedbackSlot());
       old_value = BuildNamedLoad(object, name, pair);
-      states.AddToNode(old_value, property->LoadId(),
-                       OutputFrameStateCombine::Push());
+      PrepareFrameState(old_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       stack_depth = 1;
       break;
     }
     case KEYED_PROPERTY: {
       VisitForValue(property->obj());
       VisitForValue(property->key());
-      FrameStateBeforeAndAfter states(this, property->key()->id());
+      PrepareEagerCheckpoint(property->key()->id());
       Node* key = environment()->Top();
       Node* object = environment()->Peek(1);
       VectorSlotPair pair =
           CreateVectorSlotPair(property->PropertyFeedbackSlot());
       old_value = BuildKeyedLoad(object, key, pair);
-      states.AddToNode(old_value, property->LoadId(),
-                       OutputFrameStateCombine::Push());
+      PrepareFrameState(old_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       stack_depth = 2;
       break;
     }
     case NAMED_SUPER_PROPERTY: {
       VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
       VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
-      FrameStateBeforeAndAfter states(this, property->obj()->id());
+      PrepareEagerCheckpoint(property->obj()->id());
       Node* home_object = environment()->Top();
       Node* receiver = environment()->Peek(1);
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       VectorSlotPair pair =
           CreateVectorSlotPair(property->PropertyFeedbackSlot());
       old_value = BuildNamedSuperLoad(receiver, home_object, name, pair);
-      states.AddToNode(old_value, property->LoadId(),
-                       OutputFrameStateCombine::Push());
+      PrepareFrameState(old_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       stack_depth = 2;
       break;
     }
@@ -2695,15 +2713,15 @@
       VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
       VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
       VisitForValue(property->key());
-      FrameStateBeforeAndAfter states(this, property->obj()->id());
+      PrepareEagerCheckpoint(property->obj()->id());
       Node* key = environment()->Top();
       Node* home_object = environment()->Peek(1);
       Node* receiver = environment()->Peek(2);
       VectorSlotPair pair =
           CreateVectorSlotPair(property->PropertyFeedbackSlot());
       old_value = BuildKeyedSuperLoad(receiver, home_object, key, pair);
-      states.AddToNode(old_value, property->LoadId(),
-                       OutputFrameStateCombine::Push());
+      PrepareFrameState(old_value, property->LoadId(),
+                        OutputFrameStateCombine::Push());
       stack_depth = 3;
       break;
     }
@@ -2716,7 +2734,7 @@
 
   // Create a proper eager frame state for the stores.
   environment()->Push(old_value);
-  FrameStateBeforeAndAfter store_states(this, expr->ToNumberId());
+  FrameStateBeforeAndAfter binop_states(this, expr->ToNumberId());
   old_value = environment()->Pop();
 
   // Save result for postfix expressions at correct stack depth.
@@ -2729,16 +2747,12 @@
   }
 
   // Create node to perform +1/-1 operation.
-  Node* value;
-  {
-    // TODO(bmeurer): Cleanup this feedback/bailout mess!
-    FrameStateBeforeAndAfter states(this, BailoutId::None());
-    value = BuildBinaryOp(old_value, jsgraph()->OneConstant(),
-                          expr->binary_op(), expr->CountBinOpFeedbackId());
-    // This should never deoptimize because we have converted to number before.
-    states.AddToNode(value, BailoutId::None(),
-                     OutputFrameStateCombine::Ignore());
-  }
+  // TODO(bmeurer): Cleanup this feedback/bailout mess!
+  Node* value = BuildBinaryOp(old_value, jsgraph()->OneConstant(),
+                              expr->binary_op(), expr->CountBinOpFeedbackId());
+  // This should never deoptimize because we have converted to number before.
+  binop_states.AddToNode(value, BailoutId::None(),
+                         OutputFrameStateCombine::Ignore());
 
   // Store the value.
   VectorSlotPair feedback = CreateVectorSlotPair(expr->CountSlot());
@@ -2747,7 +2761,7 @@
       Variable* variable = expr->expression()->AsVariableProxy()->var();
       environment()->Push(value);
       BuildVariableAssignment(variable, value, expr->op(), feedback,
-                              expr->AssignmentId(), store_states);
+                              expr->AssignmentId());
       environment()->Pop();
       break;
     }
@@ -2756,8 +2770,8 @@
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       Node* store = BuildNamedStore(object, name, value, feedback);
       environment()->Push(value);
-      store_states.AddToNode(store, expr->AssignmentId(),
-                             OutputFrameStateCombine::Ignore());
+      PrepareFrameState(store, expr->AssignmentId(),
+                        OutputFrameStateCombine::Ignore());
       environment()->Pop();
       break;
     }
@@ -2766,8 +2780,8 @@
       Node* object = environment()->Pop();
       Node* store = BuildKeyedStore(object, key, value, feedback);
       environment()->Push(value);
-      store_states.AddToNode(store, expr->AssignmentId(),
-                             OutputFrameStateCombine::Ignore());
+      PrepareFrameState(store, expr->AssignmentId(),
+                        OutputFrameStateCombine::Ignore());
       environment()->Pop();
       break;
     }
@@ -2777,8 +2791,8 @@
       Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
       Node* store = BuildNamedSuperStore(receiver, home_object, name, value);
       environment()->Push(value);
-      store_states.AddToNode(store, expr->AssignmentId(),
-                             OutputFrameStateCombine::Ignore());
+      PrepareFrameState(store, expr->AssignmentId(),
+                        OutputFrameStateCombine::Ignore());
       environment()->Pop();
       break;
     }
@@ -2788,8 +2802,8 @@
       Node* receiver = environment()->Pop();
       Node* store = BuildKeyedSuperStore(receiver, home_object, key, value);
       environment()->Push(value);
-      store_states.AddToNode(store, expr->AssignmentId(),
-                             OutputFrameStateCombine::Ignore());
+      PrepareFrameState(store, expr->AssignmentId(),
+                        OutputFrameStateCombine::Ignore());
       environment()->Pop();
       break;
     }
@@ -2829,19 +2843,19 @@
   const Operator* op = nullptr;
   switch (expr->op()) {
     case Token::EQ:
-      op = javascript()->Equal();
+      op = javascript()->Equal(CompareOperationHints::Any());
       break;
     case Token::EQ_STRICT:
-      op = javascript()->StrictEqual();
+      op = javascript()->StrictEqual(CompareOperationHints::Any());
       break;
     default:
       UNREACHABLE();
   }
   VisitForValue(sub_expr);
-  FrameStateBeforeAndAfter states(this, sub_expr->id());
+  PrepareEagerCheckpoint(sub_expr->id());
   Node* value_to_compare = environment()->Pop();
   Node* value = NewNode(op, value_to_compare, nil_value);
-  states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
+  PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   return ast_context()->ProduceValue(value);
 }
 
@@ -2849,11 +2863,11 @@
                                                 Expression* sub_expr,
                                                 Handle<String> check) {
   VisitTypeofExpression(sub_expr);
-  FrameStateBeforeAndAfter states(this, sub_expr->id());
+  PrepareEagerCheckpoint(sub_expr->id());
   Node* typeof_arg = NewNode(javascript()->TypeOf(), environment()->Pop());
-  Node* value = NewNode(javascript()->StrictEqual(), typeof_arg,
-                        jsgraph()->Constant(check));
-  states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
+  Node* value = NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
+                        typeof_arg, jsgraph()->Constant(check));
+  PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
   return ast_context()->ProduceValue(value);
 }
 
@@ -2874,31 +2888,38 @@
     return VisitLiteralCompareNil(expr, sub_expr, jsgraph()->NullConstant());
   }
 
+  CompareOperationHints hints;
+  if (!type_hint_analysis_ ||
+      !type_hint_analysis_->GetCompareOperationHints(
+          expr->CompareOperationFeedbackId(), &hints)) {
+    hints = CompareOperationHints::Any();
+  }
+
   const Operator* op;
   switch (expr->op()) {
     case Token::EQ:
-      op = javascript()->Equal();
+      op = javascript()->Equal(hints);
       break;
     case Token::NE:
-      op = javascript()->NotEqual();
+      op = javascript()->NotEqual(hints);
       break;
     case Token::EQ_STRICT:
-      op = javascript()->StrictEqual();
+      op = javascript()->StrictEqual(hints);
       break;
     case Token::NE_STRICT:
-      op = javascript()->StrictNotEqual();
+      op = javascript()->StrictNotEqual(hints);
       break;
     case Token::LT:
-      op = javascript()->LessThan();
+      op = javascript()->LessThan(hints);
       break;
     case Token::GT:
-      op = javascript()->GreaterThan();
+      op = javascript()->GreaterThan(hints);
       break;
     case Token::LTE:
-      op = javascript()->LessThanOrEqual();
+      op = javascript()->LessThanOrEqual(hints);
       break;
     case Token::GTE:
-      op = javascript()->GreaterThanOrEqual();
+      op = javascript()->GreaterThanOrEqual(hints);
       break;
     case Token::INSTANCEOF:
       op = javascript()->InstanceOf();
@@ -3039,9 +3060,9 @@
     // perform a non-contextual load in case the operand is a variable proxy.
     VariableProxy* proxy = expr->AsVariableProxy();
     VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
-    FrameStateBeforeAndAfter states(this, BeforeId(proxy));
+    PrepareEagerCheckpoint(BeforeId(proxy));
     Node* load =
-        BuildVariableLoad(proxy->var(), expr->id(), states, pair,
+        BuildVariableLoad(proxy->var(), expr->id(), pair,
                           OutputFrameStateCombine::Push(), INSIDE_TYPEOF);
     environment()->Push(load);
   } else {
@@ -3109,7 +3130,7 @@
 
 VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
     FeedbackVectorSlot slot) const {
-  return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot);
+  return VectorSlotPair(handle(info()->closure()->feedback_vector()), slot);
 }
 
 
@@ -3260,9 +3281,8 @@
   // Assign the object to the {arguments} variable. This should never lazy
   // deopt, so it is fine to send invalid bailout id.
   DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
-  FrameStateBeforeAndAfter states(this, BailoutId::None());
   BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(),
-                          BailoutId::None(), states);
+                          BailoutId::None());
   return object;
 }
 
@@ -3279,9 +3299,8 @@
   // Assign the object to the {rest} variable. This should never lazy
   // deopt, so it is fine to send invalid bailout id.
   DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
-  FrameStateBeforeAndAfter states(this, BailoutId::None());
   BuildVariableAssignment(rest, object, Token::ASSIGN, VectorSlotPair(),
-                          BailoutId::None(), states);
+                          BailoutId::None());
   return object;
 }
 
@@ -3294,9 +3313,8 @@
 
   // Assign the object to the {.this_function} variable. This should never lazy
   // deopt, so it is fine to send invalid bailout id.
-  FrameStateBeforeAndAfter states(this, BailoutId::None());
   BuildVariableAssignment(this_function_var, this_function, Token::INIT,
-                          VectorSlotPair(), BailoutId::None(), states);
+                          VectorSlotPair(), BailoutId::None());
   return this_function;
 }
 
@@ -3309,9 +3327,8 @@
 
   // Assign the object to the {new.target} variable. This should never lazy
   // deopt, so it is fine to send invalid bailout id.
-  FrameStateBeforeAndAfter states(this, BailoutId::None());
   BuildVariableAssignment(new_target_var, object, Token::INIT, VectorSlotPair(),
-                          BailoutId::None(), states);
+                          BailoutId::None());
   return object;
 }
 
@@ -3321,7 +3338,8 @@
                                                BailoutId bailout_id) {
   IfBuilder hole_check(this);
   Node* the_hole = jsgraph()->TheHoleConstant();
-  Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
+  Node* check = NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
+                        value, the_hole);
   hole_check.If(check);
   hole_check.Then();
   Node* error = BuildThrowReferenceError(variable, bailout_id);
@@ -3338,7 +3356,8 @@
                                                BailoutId bailout_id) {
   IfBuilder hole_check(this);
   Node* the_hole = jsgraph()->TheHoleConstant();
-  Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
+  Node* check = NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
+                        value, the_hole);
   hole_check.If(check);
   hole_check.Then();
   environment()->Push(for_hole);
@@ -3355,7 +3374,8 @@
   IfBuilder prototype_check(this);
   Node* prototype_string =
       jsgraph()->Constant(isolate()->factory()->prototype_string());
-  Node* check = NewNode(javascript()->StrictEqual(), name, prototype_string);
+  Node* check = NewNode(javascript()->StrictEqual(CompareOperationHints::Any()),
+                        name, prototype_string);
   prototype_check.If(check);
   prototype_check.Then();
   Node* error = BuildThrowStaticPrototypeError(bailout_id);
@@ -3369,7 +3389,6 @@
 
 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
                                          BailoutId bailout_id,
-                                         FrameStateBeforeAndAfter& states,
                                          const VectorSlotPair& feedback,
                                          OutputFrameStateCombine combine,
                                          TypeofMode typeof_mode) {
@@ -3382,7 +3401,7 @@
       Handle<Name> name = variable->name();
       if (Node* node = TryLoadGlobalConstant(name)) return node;
       Node* value = BuildGlobalLoad(name, feedback, typeof_mode);
-      states.AddToNode(value, bailout_id, combine);
+      PrepareFrameState(value, bailout_id, combine);
       return value;
     }
     case VariableLocation::PARAMETER:
@@ -3418,13 +3437,12 @@
     case VariableLocation::LOOKUP: {
       // Dynamic lookup of context variable (anywhere in the chain).
       Handle<String> name = variable->name();
-      if (Node* node =
-              TryLoadDynamicVariable(variable, name, bailout_id, states,
-                                     feedback, combine, typeof_mode)) {
+      if (Node* node = TryLoadDynamicVariable(variable, name, bailout_id,
+                                              feedback, combine, typeof_mode)) {
         return node;
       }
       Node* value = BuildDynamicLoad(name, typeof_mode);
-      states.AddToNode(value, bailout_id, combine);
+      PrepareFrameState(value, bailout_id, combine);
       return value;
     }
   }
@@ -3467,11 +3485,10 @@
   return nullptr;
 }
 
-
 Node* AstGraphBuilder::BuildVariableAssignment(
     Variable* variable, Node* value, Token::Value op,
     const VectorSlotPair& feedback, BailoutId bailout_id,
-    FrameStateBeforeAndAfter& states, OutputFrameStateCombine combine) {
+    OutputFrameStateCombine combine) {
   Node* the_hole = jsgraph()->TheHoleConstant();
   VariableMode mode = variable->mode();
   switch (variable->location()) {
@@ -3480,7 +3497,7 @@
       // Global var, const, or let variable.
       Handle<Name> name = variable->name();
       Node* store = BuildGlobalStore(name, value, feedback);
-      states.AddToNode(store, bailout_id, combine);
+      PrepareFrameState(store, bailout_id, combine);
       return store;
     }
     case VariableLocation::PARAMETER:
@@ -3740,11 +3757,11 @@
   Expression* expr = property->value();
   if (!FunctionLiteral::NeedsHomeObject(expr)) return value;
   Handle<Name> name = isolate()->factory()->home_object_symbol();
-  FrameStateBeforeAndAfter states(this, BailoutId::None());
   VectorSlotPair feedback =
       CreateVectorSlotPair(property->GetSlot(slot_number));
   Node* store = BuildNamedStore(value, name, home_object, feedback);
-  states.AddToNode(store, BailoutId::None(), OutputFrameStateCombine::Ignore());
+  PrepareFrameState(store, BailoutId::None(),
+                    OutputFrameStateCombine::Ignore());
   return store;
 }
 
@@ -3881,11 +3898,12 @@
   return nullptr;
 }
 
-
-Node* AstGraphBuilder::TryLoadDynamicVariable(
-    Variable* variable, Handle<String> name, BailoutId bailout_id,
-    FrameStateBeforeAndAfter& states, const VectorSlotPair& feedback,
-    OutputFrameStateCombine combine, TypeofMode typeof_mode) {
+Node* AstGraphBuilder::TryLoadDynamicVariable(Variable* variable,
+                                              Handle<String> name,
+                                              BailoutId bailout_id,
+                                              const VectorSlotPair& feedback,
+                                              OutputFrameStateCombine combine,
+                                              TypeofMode typeof_mode) {
   VariableMode mode = variable->mode();
 
   if (mode == DYNAMIC_GLOBAL) {
@@ -3907,8 +3925,9 @@
       Node* load = NewNode(
           javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
           current_context());
-      Node* check = NewNode(javascript()->StrictEqual(), load,
-                            jsgraph()->TheHoleConstant());
+      Node* check =
+          NewNode(javascript()->StrictEqual(CompareOperationHints::Any()), load,
+                  jsgraph()->TheHoleConstant());
       fast_block.BreakUnless(check, BranchHint::kTrue);
     }
 
@@ -3918,7 +3937,7 @@
     } else {
       // Perform global slot load.
       Node* fast = BuildGlobalLoad(name, feedback, typeof_mode);
-      states.AddToNode(fast, bailout_id, combine);
+      PrepareFrameState(fast, bailout_id, combine);
       environment()->Push(fast);
     }
     slow_block.Break();
@@ -3927,7 +3946,7 @@
 
     // Slow case, because variable potentially shadowed. Perform dynamic lookup.
     Node* slow = BuildDynamicLoad(name, typeof_mode);
-    states.AddToNode(slow, bailout_id, combine);
+    PrepareFrameState(slow, bailout_id, combine);
     environment()->Push(slow);
     slow_block.EndBlock();
 
@@ -3953,16 +3972,17 @@
       Node* load = NewNode(
           javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
           current_context());
-      Node* check = NewNode(javascript()->StrictEqual(), load,
-                            jsgraph()->TheHoleConstant());
+      Node* check =
+          NewNode(javascript()->StrictEqual(CompareOperationHints::Any()), load,
+                  jsgraph()->TheHoleConstant());
       fast_block.BreakUnless(check, BranchHint::kTrue);
     }
 
     // Fast case, because variable is not shadowed. Perform context slot load.
     Variable* local = variable->local_if_not_shadowed();
     DCHECK(local->location() == VariableLocation::CONTEXT);  // Must be context.
-    Node* fast = BuildVariableLoad(local, bailout_id, states, feedback, combine,
-                                   typeof_mode);
+    Node* fast =
+        BuildVariableLoad(local, bailout_id, feedback, combine, typeof_mode);
     environment()->Push(fast);
     slow_block.Break();
     environment()->Pop();
@@ -3970,7 +3990,7 @@
 
     // Slow case, because variable potentially shadowed. Perform dynamic lookup.
     Node* slow = BuildDynamicLoad(name, typeof_mode);
-    states.AddToNode(slow, bailout_id, combine);
+    PrepareFrameState(slow, bailout_id, combine);
     environment()->Push(slow);
     slow_block.EndBlock();
 
@@ -4053,6 +4073,20 @@
   }
 }
 
+void AstGraphBuilder::PrepareEagerCheckpoint(BailoutId ast_id) {
+  if (environment()->GetEffectDependency()->opcode() == IrOpcode::kCheckpoint) {
+    // We skip preparing a checkpoint if there already is one the current effect
+    // dependency. This is just an optimization and not need for correctness.
+    return;
+  }
+  if (ast_id != BailoutId::None()) {
+    Node* node = NewNode(common()->Checkpoint());
+    DCHECK_EQ(IrOpcode::kDead,
+              NodeProperties::GetFrameStateInput(node, 0)->opcode());
+    NodeProperties::ReplaceFrameStateInput(node, 0,
+                                           environment()->Checkpoint(ast_id));
+  }
+}
 
 BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
     IterationStatement* stmt) {
@@ -4298,7 +4332,6 @@
 }
 
 
-// TODO(mstarzinger): Revisit this once we have proper effect states.
 Node* AstGraphBuilder::NewEffectPhi(int count, Node* input, Node* control) {
   const Operator* phi_op = common()->EffectPhi(count);
   Node** buffer = EnsureInputBufferSize(count + 1);