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/escape-analysis.cc b/src/compiler/escape-analysis.cc
index d11c3ab..9409a27 100644
--- a/src/compiler/escape-analysis.cc
+++ b/src/compiler/escape-analysis.cc
@@ -794,6 +794,12 @@
         break;
       case IrOpcode::kSelect:
       case IrOpcode::kTypeGuard:
+      // TODO(mstarzinger): The following list of operators will eventually be
+      // handled by the EscapeAnalysisReducer (similar to ObjectIsSmi).
+      case IrOpcode::kObjectIsCallable:
+      case IrOpcode::kObjectIsNumber:
+      case IrOpcode::kObjectIsString:
+      case IrOpcode::kObjectIsUndetectable:
         if (SetEscaped(rep)) {
           TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
                 rep->id(), rep->op()->mnemonic(), use->id(),
@@ -843,6 +849,7 @@
 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
                                Zone* zone)
     : zone_(zone),
+      slot_not_analyzed_(graph->NewNode(common->NumberConstant(0x1c0debad))),
       common_(common),
       status_analysis_(new (zone) EscapeStatusAnalysis(this, graph, zone)),
       virtual_states_(zone),
@@ -1321,11 +1328,24 @@
   return false;
 }
 
-int EscapeAnalysis::OffsetFromAccess(Node* node) {
-  DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0);
-  return OpParameter<FieldAccess>(node).offset / kPointerSize;
+namespace {
+
+int OffsetForFieldAccess(Node* node) {
+  FieldAccess access = FieldAccessOf(node->op());
+  DCHECK_EQ(access.offset % kPointerSize, 0);
+  return access.offset / kPointerSize;
 }
 
+int OffsetForElementAccess(Node* node, int index) {
+  ElementAccess access = ElementAccessOf(node->op());
+  DCHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
+            kPointerSizeLog2);
+  DCHECK_EQ(access.header_size % kPointerSize, 0);
+  return access.header_size / kPointerSize + index;
+}
+
+}  // namespace
+
 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load,
                                         VirtualState* state) {
   TRACE("Load #%d from phi #%d", load->id(), from->id());
@@ -1368,11 +1388,9 @@
   Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0));
   VirtualState* state = virtual_states_[node->id()];
   if (VirtualObject* object = GetVirtualObject(state, from)) {
-    int offset = OffsetFromAccess(node);
-    if (!object->IsTracked() ||
-        static_cast<size_t>(offset) >= object->field_count()) {
-      return;
-    }
+    if (!object->IsTracked()) return;
+    int offset = OffsetForFieldAccess(node);
+    if (static_cast<size_t>(offset) >= object->field_count()) return;
     Node* value = object->GetField(offset);
     if (value) {
       value = ResolveReplacement(value);
@@ -1380,8 +1398,8 @@
     // Record that the load has this alias.
     UpdateReplacement(state, node, value);
   } else if (from->opcode() == IrOpcode::kPhi &&
-             OpParameter<FieldAccess>(node).offset % kPointerSize == 0) {
-    int offset = OffsetFromAccess(node);
+             FieldAccessOf(node->op()).offset % kPointerSize == 0) {
+    int offset = OffsetForFieldAccess(node);
     // Only binary phis are supported for now.
     ProcessLoadFromPhi(offset, from, node, state);
   } else {
@@ -1400,19 +1418,11 @@
          index_node->opcode() != IrOpcode::kInt64Constant &&
          index_node->opcode() != IrOpcode::kFloat32Constant &&
          index_node->opcode() != IrOpcode::kFloat64Constant);
-  ElementAccess access = OpParameter<ElementAccess>(node);
   if (index.HasValue()) {
-    int offset = index.Value() + access.header_size / kPointerSize;
     if (VirtualObject* object = GetVirtualObject(state, from)) {
-      CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
-               kPointerSizeLog2);
-      CHECK_EQ(access.header_size % kPointerSize, 0);
-
-      if (!object->IsTracked() ||
-          static_cast<size_t>(offset) >= object->field_count()) {
-        return;
-      }
-
+      if (!object->IsTracked()) return;
+      int offset = OffsetForElementAccess(node, index.Value());
+      if (static_cast<size_t>(offset) >= object->field_count()) return;
       Node* value = object->GetField(offset);
       if (value) {
         value = ResolveReplacement(value);
@@ -1420,8 +1430,7 @@
       // Record that the load has this alias.
       UpdateReplacement(state, node, value);
     } else if (from->opcode() == IrOpcode::kPhi) {
-      ElementAccess access = OpParameter<ElementAccess>(node);
-      int offset = index.Value() + access.header_size / kPointerSize;
+      int offset = OffsetForElementAccess(node, index.Value());
       ProcessLoadFromPhi(offset, from, node, state);
     } else {
       UpdateReplacement(state, node, nullptr);
@@ -1443,14 +1452,23 @@
   ForwardVirtualState(node);
   Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0));
   VirtualState* state = virtual_states_[node->id()];
-  VirtualObject* obj = GetVirtualObject(state, to);
-  int offset = OffsetFromAccess(node);
-  if (obj && obj->IsTracked() &&
-      static_cast<size_t>(offset) < obj->field_count()) {
+  if (VirtualObject* object = GetVirtualObject(state, to)) {
+    if (!object->IsTracked()) return;
+    int offset = OffsetForFieldAccess(node);
+    if (static_cast<size_t>(offset) >= object->field_count()) return;
     Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1));
-    if (obj->GetField(offset) != val) {
-      obj = CopyForModificationAt(obj, state, node);
-      obj->SetField(offset, val);
+    // TODO(mstarzinger): The following is a workaround to not track the code
+    // entry field in virtual JSFunction objects. We only ever store the inner
+    // pointer into the compile lazy stub in this field and the deoptimizer has
+    // this assumption hard-coded in {TranslatedState::MaterializeAt} as well.
+    if (val->opcode() == IrOpcode::kInt32Constant ||
+        val->opcode() == IrOpcode::kInt64Constant) {
+      DCHECK_EQ(JSFunction::kCodeEntryOffset, FieldAccessOf(node->op()).offset);
+      val = slot_not_analyzed_;
+    }
+    if (object->GetField(offset) != val) {
+      object = CopyForModificationAt(object, state, node);
+      object->SetField(offset, val);
     }
   }
 }
@@ -1465,20 +1483,16 @@
          index_node->opcode() != IrOpcode::kInt64Constant &&
          index_node->opcode() != IrOpcode::kFloat32Constant &&
          index_node->opcode() != IrOpcode::kFloat64Constant);
-  ElementAccess access = OpParameter<ElementAccess>(node);
   VirtualState* state = virtual_states_[node->id()];
-  VirtualObject* obj = GetVirtualObject(state, to);
   if (index.HasValue()) {
-    int offset = index.Value() + access.header_size / kPointerSize;
-    if (obj && obj->IsTracked() &&
-        static_cast<size_t>(offset) < obj->field_count()) {
-      CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
-               kPointerSizeLog2);
-      CHECK_EQ(access.header_size % kPointerSize, 0);
+    if (VirtualObject* object = GetVirtualObject(state, to)) {
+      if (!object->IsTracked()) return;
+      int offset = OffsetForElementAccess(node, index.Value());
+      if (static_cast<size_t>(offset) >= object->field_count()) return;
       Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2));
-      if (obj->GetField(offset) != val) {
-        obj = CopyForModificationAt(obj, state, node);
-        obj->SetField(offset, val);
+      if (object->GetField(offset) != val) {
+        object = CopyForModificationAt(object, state, node);
+        object->SetField(offset, val);
       }
     }
   } else {
@@ -1490,12 +1504,13 @@
           to->id(), to->op()->mnemonic(), node->id(), index_node->id(),
           index_node->op()->mnemonic());
     }
-    if (obj && obj->IsTracked()) {
-      if (!obj->AllFieldsClear()) {
-        obj = CopyForModificationAt(obj, state, node);
-        obj->ClearAllFields();
+    if (VirtualObject* object = GetVirtualObject(state, to)) {
+      if (!object->IsTracked()) return;
+      if (!object->AllFieldsClear()) {
+        object = CopyForModificationAt(object, state, node);
+        object->ClearAllFields();
         TRACE("Cleared all fields of @%d:#%d\n",
-              status_analysis_->GetAlias(obj->id()), obj->id());
+              status_analysis_->GetAlias(object->id()), object->id());
       }
     }
   }