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) {