Merge V8 5.2.361.47  DO NOT MERGE

https://chromium.googlesource.com/v8/v8/+/5.2.361.47

FPIIM-449

Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc
index d1353d2..fbc064c 100644
--- a/src/compiler/js-native-context-specialization.cc
+++ b/src/compiler/js-native-context-specialization.cc
@@ -157,13 +157,7 @@
     // Perform map check on {receiver}.
     Type* receiver_type = access_info.receiver_type();
     if (receiver_type->Is(Type::String())) {
-      // Emit an instance type check for strings.
-      Node* receiver_instance_type = this_effect = graph()->NewNode(
-          simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
-          receiver_map, this_effect, fallthrough_control);
-      Node* check =
-          graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type,
-                           jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
+      Node* check = graph()->NewNode(simplified()->ObjectIsString(), receiver);
       if (j == access_infos.size() - 1) {
         this_control =
             graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
@@ -270,7 +264,7 @@
                                    1 << JSArrayBuffer::WasNeutered::kShift)),
               jsgraph()->Int32Constant(0));
           this_control =
-              graph()->NewNode(common()->DeoptimizeIf(), check, frame_state,
+              graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
                                this_effect, this_control);
           break;
         }
@@ -285,8 +279,9 @@
             simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
             this_storage, this_effect, this_control);
       }
-      FieldAccess field_access = {kTaggedBase, field_index.offset(), name,
-                                  field_type, MachineType::AnyTagged()};
+      FieldAccess field_access = {
+          kTaggedBase, field_index.offset(),     name,
+          field_type,  MachineType::AnyTagged(), kFullWriteBarrier};
       if (access_mode == AccessMode::kLoad) {
         if (field_type->Is(Type::UntaggedFloat64())) {
           if (!field_index.is_inobject() || field_index.is_hidden_field() ||
@@ -310,26 +305,28 @@
           this_control =
               graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
                                this_effect, this_control);
-          this_value = graph()->NewNode(common()->Guard(Type::Number()),
+          this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
                                         this_value, this_control);
 
           if (!field_index.is_inobject() || field_index.is_hidden_field() ||
               !FLAG_unbox_double_fields) {
             if (access_info.HasTransitionMap()) {
               // Allocate a MutableHeapNumber for the new property.
-              Callable callable =
-                  CodeFactory::AllocateMutableHeapNumber(isolate());
-              CallDescriptor* desc = Linkage::GetStubCallDescriptor(
-                  isolate(), jsgraph()->zone(), callable.descriptor(), 0,
-                  CallDescriptor::kNoFlags, Operator::kNoThrow);
-              Node* this_box = this_effect = graph()->NewNode(
-                  common()->Call(desc),
-                  jsgraph()->HeapConstant(callable.code()),
-                  jsgraph()->NoContextConstant(), this_effect, this_control);
+              this_effect =
+                  graph()->NewNode(common()->BeginRegion(), this_effect);
+              Node* this_box = this_effect =
+                  graph()->NewNode(simplified()->Allocate(NOT_TENURED),
+                                   jsgraph()->Constant(HeapNumber::kSize),
+                                   this_effect, this_control);
+              this_effect = graph()->NewNode(
+                  simplified()->StoreField(AccessBuilder::ForMap()), this_box,
+                  jsgraph()->HeapConstant(factory()->mutable_heap_number_map()),
+                  this_effect, this_control);
               this_effect = graph()->NewNode(
                   simplified()->StoreField(AccessBuilder::ForHeapNumberValue()),
                   this_box, this_value, this_effect, this_control);
-              this_value = this_box;
+              this_value = this_effect = graph()->NewNode(
+                  common()->FinishRegion(), this_box, this_effect);
 
               field_access.type = Type::TaggedPointer();
             } else {
@@ -351,8 +348,9 @@
           this_control =
               graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
                                this_effect, this_control);
-          this_value = graph()->NewNode(common()->Guard(type_cache_.kSmi),
-                                        this_value, this_control);
+          this_value =
+              graph()->NewNode(simplified()->TypeGuard(type_cache_.kSmi),
+                               this_value, this_control);
         } else if (field_type->Is(Type::TaggedPointer())) {
           Node* check =
               graph()->NewNode(simplified()->ObjectIsSmi(), this_value);
@@ -431,25 +429,29 @@
     AccessMode access_mode, LanguageMode language_mode) {
   DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
          node->opcode() == IrOpcode::kJSStoreNamed);
+  Node* const receiver = NodeProperties::GetValueInput(node, 0);
+  Node* const effect = NodeProperties::GetEffectInput(node);
 
   // Check if the {nexus} reports type feedback for the IC.
   if (nexus.IsUninitialized()) {
     if ((flags() & kDeoptimizationEnabled) &&
         (flags() & kBailoutOnUninitialized)) {
-      // TODO(turbofan): Implement all eager bailout points correctly in
-      // the graph builder.
-      Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
-      if (!OpParameter<FrameStateInfo>(frame_state).bailout_id().IsNone()) {
-        return ReduceSoftDeoptimize(node);
-      }
+      return ReduceSoftDeoptimize(node);
     }
     return NoChange();
   }
 
   // Extract receiver maps from the IC using the {nexus}.
   MapHandleList receiver_maps;
-  if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
-  DCHECK_LT(0, receiver_maps.length());
+  if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
+    return NoChange();
+  } else if (receiver_maps.length() == 0) {
+    if ((flags() & kDeoptimizationEnabled) &&
+        (flags() & kBailoutOnUninitialized)) {
+      return ReduceSoftDeoptimize(node);
+    }
+    return NoChange();
+  }
 
   // Try to lower the named access based on the {receiver_maps}.
   return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
@@ -460,8 +462,33 @@
 Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
   DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
   NamedAccess const& p = NamedAccessOf(node->op());
+  Node* const receiver = NodeProperties::GetValueInput(node, 0);
   Node* const value = jsgraph()->Dead();
 
+  // Check if we have a constant receiver.
+  HeapObjectMatcher m(receiver);
+  if (m.HasValue()) {
+    // Optimize "prototype" property of functions.
+    if (m.Value()->IsJSFunction() &&
+        p.name().is_identical_to(factory()->prototype_string())) {
+      Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
+      if (function->has_initial_map()) {
+        // We need to add a code dependency on the initial map of the
+        // {function} in order to be notified about changes to the
+        // "prototype" of {function}, so it doesn't make sense to
+        // continue unless deoptimization is enabled.
+        if (flags() & kDeoptimizationEnabled) {
+          Handle<Map> initial_map(function->initial_map(), isolate());
+          dependencies()->AssumeInitialMapCantChange(initial_map);
+          Handle<Object> prototype(initial_map->prototype(), isolate());
+          Node* value = jsgraph()->Constant(prototype);
+          ReplaceWithValue(node, value);
+          return Replace(value);
+        }
+      }
+    }
+  }
+
   // Extract receiver maps from the LOAD_IC using the LoadICNexus.
   if (!p.feedback().IsValid()) return NoChange();
   LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
@@ -664,8 +691,8 @@
           graph()->NewNode(simplified()->ObjectIsNumber(), this_index);
       this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
                                       frame_state, this_effect, this_control);
-      this_index = graph()->NewNode(common()->Guard(Type::Number()), this_index,
-                                    this_control);
+      this_index = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
+                                    this_index, this_control);
     }
 
     // Convert the {index} to an unsigned32 value and check if the result is
@@ -729,7 +756,8 @@
       element_type = type_cache_.kSmi;
     }
     ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize,
-                                    element_type, element_machine_type};
+                                    element_type, element_machine_type,
+                                    kFullWriteBarrier};
 
     // Access the actual element.
     // TODO(bmeurer): Refactor this into separate methods or even a separate
@@ -786,8 +814,8 @@
         }
         // Rename the result to represent the actual type (not polluted by the
         // hole).
-        this_value = graph()->NewNode(common()->Guard(element_type), this_value,
-                                      this_control);
+        this_value = graph()->NewNode(simplified()->TypeGuard(element_type),
+                                      this_value, this_control);
       } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
         // Perform the hole check on the result.
         Node* check =
@@ -820,14 +848,14 @@
         Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value);
         this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
                                         frame_state, this_effect, this_control);
-        this_value = graph()->NewNode(common()->Guard(type_cache_.kSmi),
+        this_value = graph()->NewNode(simplified()->TypeGuard(type_cache_.kSmi),
                                       this_value, this_control);
       } else if (IsFastDoubleElementsKind(elements_kind)) {
         Node* check =
             graph()->NewNode(simplified()->ObjectIsNumber(), this_value);
         this_control = graph()->NewNode(common()->DeoptimizeUnless(), check,
                                         frame_state, this_effect, this_control);
-        this_value = graph()->NewNode(common()->Guard(Type::Number()),
+        this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()),
                                       this_value, this_control);
       }
       this_effect = graph()->NewNode(simplified()->StoreElement(element_access),
@@ -873,25 +901,29 @@
     KeyedAccessStoreMode store_mode) {
   DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
          node->opcode() == IrOpcode::kJSStoreProperty);
+  Node* const receiver = NodeProperties::GetValueInput(node, 0);
+  Node* const effect = NodeProperties::GetEffectInput(node);
 
   // Check if the {nexus} reports type feedback for the IC.
   if (nexus.IsUninitialized()) {
     if ((flags() & kDeoptimizationEnabled) &&
         (flags() & kBailoutOnUninitialized)) {
-      // TODO(turbofan): Implement all eager bailout points correctly in
-      // the graph builder.
-      Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
-      if (!OpParameter<FrameStateInfo>(frame_state).bailout_id().IsNone()) {
-        return ReduceSoftDeoptimize(node);
-      }
+      return ReduceSoftDeoptimize(node);
     }
     return NoChange();
   }
 
   // Extract receiver maps from the {nexus}.
   MapHandleList receiver_maps;
-  if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange();
-  DCHECK_LT(0, receiver_maps.length());
+  if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
+    return NoChange();
+  } else if (receiver_maps.length() == 0) {
+    if ((flags() & kDeoptimizationEnabled) &&
+        (flags() & kBailoutOnUninitialized)) {
+      return ReduceSoftDeoptimize(node);
+    }
+    return NoChange();
+  }
 
   // Optimize access for constant {index}.
   HeapObjectMatcher mindex(index);
@@ -995,6 +1027,84 @@
   }
 }
 
+bool JSNativeContextSpecialization::ExtractReceiverMaps(
+    Node* receiver, Node* effect, FeedbackNexus const& nexus,
+    MapHandleList* receiver_maps) {
+  DCHECK_EQ(0, receiver_maps->length());
+  // See if we can infer a concrete type for the {receiver}.
+  Handle<Map> receiver_map;
+  if (InferReceiverMap(receiver, effect).ToHandle(&receiver_map)) {
+    // We can assume that the {receiver} still has the infered {receiver_map}.
+    receiver_maps->Add(receiver_map);
+    return true;
+  }
+  // Try to extract some maps from the {nexus}.
+  if (nexus.ExtractMaps(receiver_maps) != 0) {
+    // Try to filter impossible candidates based on infered root map.
+    if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
+      for (int i = receiver_maps->length(); --i >= 0;) {
+        if (receiver_maps->at(i)->FindRootMap() != *receiver_map) {
+          receiver_maps->Remove(i);
+        }
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver,
+                                                                 Node* effect) {
+  NodeMatcher m(receiver);
+  if (m.IsJSCreate()) {
+    HeapObjectMatcher mtarget(m.InputAt(0));
+    HeapObjectMatcher mnewtarget(m.InputAt(1));
+    if (mtarget.HasValue() && mnewtarget.HasValue()) {
+      Handle<JSFunction> constructor =
+          Handle<JSFunction>::cast(mtarget.Value());
+      if (constructor->has_initial_map()) {
+        Handle<Map> initial_map(constructor->initial_map(), isolate());
+        if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
+          // Walk up the {effect} chain to see if the {receiver} is the
+          // dominating effect and there's no other observable write in
+          // between.
+          while (true) {
+            if (receiver == effect) return initial_map;
+            if (!effect->op()->HasProperty(Operator::kNoWrite) ||
+                effect->op()->EffectInputCount() != 1) {
+              break;
+            }
+            effect = NodeProperties::GetEffectInput(effect);
+          }
+        }
+      }
+    }
+  }
+  return MaybeHandle<Map>();
+}
+
+MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
+    Node* receiver) {
+  HeapObjectMatcher m(receiver);
+  if (m.HasValue()) {
+    return handle(m.Value()->map()->FindRootMap(), isolate());
+  } else if (m.IsJSCreate()) {
+    HeapObjectMatcher mtarget(m.InputAt(0));
+    HeapObjectMatcher mnewtarget(m.InputAt(1));
+    if (mtarget.HasValue() && mnewtarget.HasValue()) {
+      Handle<JSFunction> constructor =
+          Handle<JSFunction>::cast(mtarget.Value());
+      if (constructor->has_initial_map()) {
+        Handle<Map> initial_map(constructor->initial_map(), isolate());
+        if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
+          DCHECK_EQ(*initial_map, initial_map->FindRootMap());
+          return initial_map;
+        }
+      }
+    }
+  }
+  return MaybeHandle<Map>();
+}
 
 MaybeHandle<Context> JSNativeContextSpecialization::GetNativeContext(
     Node* node) {