Commit 23f087cc authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Precompute inlineability of array resize builtins per map.

Bug: v8:7790
Change-Id: Iad109ee7112b8c21b4fd89e189e68911b6aa4968
Reviewed-on: https://chromium-review.googlesource.com/c/1397708Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58661}
parent 82c0f925
...@@ -4308,32 +4308,6 @@ Reduction JSCallReducer::ReduceSoftDeoptimize(Node* node, ...@@ -4308,32 +4308,6 @@ Reduction JSCallReducer::ReduceSoftDeoptimize(Node* node,
return Changed(node); return Changed(node);
} }
namespace {
// TODO(turbofan): This was copied from old compiler, might be too restrictive.
bool IsReadOnlyLengthDescriptor(Isolate* isolate, Handle<Map> jsarray_map) {
DCHECK(!jsarray_map->is_dictionary_map());
Handle<Name> length_string = isolate->factory()->length_string();
DescriptorArray descriptors = jsarray_map->instance_descriptors();
int number = descriptors->Search(*length_string, *jsarray_map);
DCHECK_NE(DescriptorArray::kNotFound, number);
return descriptors->GetDetails(number).IsReadOnly();
}
// TODO(turbofan): This was copied from old compiler, might be too restrictive.
bool CanInlineArrayResizeOperation(Isolate* isolate, MapRef& receiver_map) {
receiver_map.SerializePrototype();
if (!receiver_map.prototype().IsJSArray()) return false;
JSArrayRef receiver_prototype = receiver_map.prototype().AsJSArray();
return receiver_map.instance_type() == JS_ARRAY_TYPE &&
IsFastElementsKind(receiver_map.elements_kind()) &&
!receiver_map.is_dictionary_map() && receiver_map.is_extensible() &&
isolate->IsAnyInitialArrayPrototype(receiver_prototype.object()) &&
!IsReadOnlyLengthDescriptor(isolate, receiver_map.object());
}
} // namespace
// ES6 section 22.1.3.18 Array.prototype.push ( ) // ES6 section 22.1.3.18 Array.prototype.push ( )
Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) { Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
...@@ -4342,18 +4316,11 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) { ...@@ -4342,18 +4316,11 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
return NoChange(); return NoChange();
} }
PropertyCellRef no_elements_protector(broker(),
factory()->no_elements_protector());
if (no_elements_protector.value().AsSmi() != Isolate::kProtectorValid) {
return NoChange();
}
int const num_values = node->op()->ValueInputCount() - 2; int const num_values = node->op()->ValueInputCount() - 2;
Node* receiver = NodeProperties::GetValueInput(node, 1); Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
// Try to determine the {receiver} map(s).
ZoneHandleSet<Map> receiver_maps; ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result = NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(broker(), receiver, effect, NodeProperties::InferReceiverMaps(broker(), receiver, effect,
...@@ -4362,18 +4329,15 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) { ...@@ -4362,18 +4329,15 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
DCHECK_NE(0, receiver_maps.size()); DCHECK_NE(0, receiver_maps.size());
ElementsKind kind = receiver_maps[0]->elements_kind(); ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> map : receiver_maps) { for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map); MapRef receiver_map(broker(), map);
receiver_map.SerializePrototype(); if (!receiver_map.supports_fast_array_resize()) return NoChange();
if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
return NoChange();
if (!UnionElementsKindUptoPackedness(&kind, receiver_map.elements_kind())) if (!UnionElementsKindUptoPackedness(&kind, receiver_map.elements_kind()))
return NoChange(); return NoChange();
} }
// Install code dependencies on the {receiver} global array protector cell. dependencies()->DependOnProtector(
dependencies()->DependOnProtector(no_elements_protector); PropertyCellRef(broker(), factory()->no_elements_protector()));
// If the {receiver_maps} information is not reliable, we need // If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps. // to check that the {receiver} still has one of these maps.
...@@ -4461,12 +4425,6 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) { ...@@ -4461,12 +4425,6 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
return NoChange(); return NoChange();
} }
PropertyCellRef no_elements_protector(broker(),
factory()->no_elements_protector());
if (no_elements_protector.value().AsSmi() != Isolate::kProtectorValid) {
return NoChange();
}
Node* receiver = NodeProperties::GetValueInput(node, 1); Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
...@@ -4481,9 +4439,7 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) { ...@@ -4481,9 +4439,7 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
ElementsKind kind = receiver_maps[0]->elements_kind(); ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> map : receiver_maps) { for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map); MapRef receiver_map(broker(), map);
receiver_map.SerializePrototype(); if (!receiver_map.supports_fast_array_resize()) return NoChange();
if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
return NoChange();
// TODO(turbofan): Extend this to also handle fast holey double elements // TODO(turbofan): Extend this to also handle fast holey double elements
// once we got the hole NaN mess sorted out in TurboFan/V8. // once we got the hole NaN mess sorted out in TurboFan/V8.
if (receiver_map.elements_kind() == HOLEY_DOUBLE_ELEMENTS) if (receiver_map.elements_kind() == HOLEY_DOUBLE_ELEMENTS)
...@@ -4492,8 +4448,8 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) { ...@@ -4492,8 +4448,8 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
return NoChange(); return NoChange();
} }
// Install code dependencies on the {receiver} global array protector cell. dependencies()->DependOnProtector(
dependencies()->DependOnProtector(no_elements_protector); PropertyCellRef(broker(), factory()->no_elements_protector()));
// If the {receiver_maps} information is not reliable, we need // If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps. // to check that the {receiver} still has one of these maps.
...@@ -4583,12 +4539,6 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) { ...@@ -4583,12 +4539,6 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
return NoChange(); return NoChange();
} }
PropertyCellRef no_elements_protector(broker(),
factory()->no_elements_protector());
if (no_elements_protector.value().AsSmi() != Isolate::kProtectorValid) {
return NoChange();
}
Node* target = NodeProperties::GetValueInput(node, 0); Node* target = NodeProperties::GetValueInput(node, 0);
Node* receiver = NodeProperties::GetValueInput(node, 1); Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* context = NodeProperties::GetContextInput(node); Node* context = NodeProperties::GetContextInput(node);
...@@ -4606,9 +4556,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) { ...@@ -4606,9 +4556,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
ElementsKind kind = receiver_maps[0]->elements_kind(); ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> map : receiver_maps) { for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map); MapRef receiver_map(broker(), map);
receiver_map.SerializePrototype(); if (!receiver_map.supports_fast_array_resize()) return NoChange();
if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
return NoChange();
// TODO(turbofan): Extend this to also handle fast holey double elements // TODO(turbofan): Extend this to also handle fast holey double elements
// once we got the hole NaN mess sorted out in TurboFan/V8. // once we got the hole NaN mess sorted out in TurboFan/V8.
if (receiver_map.elements_kind() == HOLEY_DOUBLE_ELEMENTS) if (receiver_map.elements_kind() == HOLEY_DOUBLE_ELEMENTS)
...@@ -4617,8 +4565,8 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) { ...@@ -4617,8 +4565,8 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
return NoChange(); return NoChange();
} }
// Install code dependencies on the {receiver} global array protector cell. dependencies()->DependOnProtector(
dependencies()->DependOnProtector(no_elements_protector); PropertyCellRef(broker(), factory()->no_elements_protector()));
// If the {receiver_maps} information is not reliable, we need // If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps. // to check that the {receiver} still has one of these maps.
......
...@@ -649,6 +649,9 @@ class MapData : public HeapObjectData { ...@@ -649,6 +649,9 @@ class MapData : public HeapObjectData {
int constructor_function_index() const { return constructor_function_index_; } int constructor_function_index() const { return constructor_function_index_; }
int NextFreePropertyIndex() const { return next_free_property_index_; } int NextFreePropertyIndex() const { return next_free_property_index_; }
int UnusedPropertyFields() const { return unused_property_fields_; } int UnusedPropertyFields() const { return unused_property_fields_; }
bool supports_fast_array_resize() const {
return supports_fast_array_resize_;
}
// Extra information. // Extra information.
...@@ -691,6 +694,7 @@ class MapData : public HeapObjectData { ...@@ -691,6 +694,7 @@ class MapData : public HeapObjectData {
int const constructor_function_index_; int const constructor_function_index_;
int const next_free_property_index_; int const next_free_property_index_;
int const unused_property_fields_; int const unused_property_fields_;
bool const supports_fast_array_resize_;
bool serialized_elements_kind_generalizations_ = false; bool serialized_elements_kind_generalizations_ = false;
ZoneVector<MapData*> elements_kind_generalizations_; ZoneVector<MapData*> elements_kind_generalizations_;
...@@ -752,6 +756,28 @@ HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage, ...@@ -752,6 +756,28 @@ HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
CHECK(broker->SerializingAllowed()); CHECK(broker->SerializingAllowed());
} }
namespace {
bool IsReadOnlyLengthDescriptor(Isolate* isolate, Handle<Map> jsarray_map) {
DCHECK(!jsarray_map->is_dictionary_map());
Handle<Name> length_string = isolate->factory()->length_string();
DescriptorArray descriptors = jsarray_map->instance_descriptors();
int number = descriptors->Search(*length_string, *jsarray_map);
DCHECK_NE(DescriptorArray::kNotFound, number);
return descriptors->GetDetails(number).IsReadOnly();
}
bool SupportsFastArrayResize(Isolate* isolate, Handle<Map> map) {
return map->instance_type() == JS_ARRAY_TYPE &&
IsFastElementsKind(map->elements_kind()) && map->is_extensible() &&
map->prototype()->IsJSArray() &&
isolate->IsAnyInitialArrayPrototype(
handle(JSArray::cast(map->prototype()), isolate)) &&
!map->is_dictionary_map() &&
!IsReadOnlyLengthDescriptor(isolate, map) &&
isolate->IsNoElementsProtectorIntact();
}
} // namespace
MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object) MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object)
: HeapObjectData(broker, storage, object), : HeapObjectData(broker, storage, object),
instance_type_(object->instance_type()), instance_type_(object->instance_type()),
...@@ -773,6 +799,8 @@ MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object) ...@@ -773,6 +799,8 @@ MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object)
: Map::kNoConstructorFunctionIndex), : Map::kNoConstructorFunctionIndex),
next_free_property_index_(object->NextFreePropertyIndex()), next_free_property_index_(object->NextFreePropertyIndex()),
unused_property_fields_(object->UnusedPropertyFields()), unused_property_fields_(object->UnusedPropertyFields()),
supports_fast_array_resize_(
SupportsFastArrayResize(broker->isolate(), object)),
elements_kind_generalizations_(broker->zone()) {} elements_kind_generalizations_(broker->zone()) {}
JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage, JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
...@@ -1819,6 +1847,15 @@ base::Optional<MapRef> MapRef::AsElementsKind(ElementsKind kind) const { ...@@ -1819,6 +1847,15 @@ base::Optional<MapRef> MapRef::AsElementsKind(ElementsKind kind) const {
return base::Optional<MapRef>(); return base::Optional<MapRef>();
} }
bool MapRef::supports_fast_array_resize() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation handle_allocation;
return SupportsFastArrayResize(broker()->isolate(), object());
}
return data()->AsMap()->supports_fast_array_resize();
}
int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const { int JSFunctionRef::InitialMapInstanceSizeWithMinSlack() const {
if (broker()->mode() == JSHeapBroker::kDisabled) { if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference; AllowHandleDereference allow_handle_dereference;
......
...@@ -433,6 +433,7 @@ class MapRef : public HeapObjectRef { ...@@ -433,6 +433,7 @@ class MapRef : public HeapObjectRef {
bool is_undetectable() const; bool is_undetectable() const;
bool is_callable() const; bool is_callable() const;
bool has_hidden_prototype() const; bool has_hidden_prototype() const;
bool supports_fast_array_resize() const;
#define DEF_TESTER(Type, ...) bool Is##Type##Map() const; #define DEF_TESTER(Type, ...) bool Is##Type##Map() const;
INSTANCE_TYPE_CHECKERS(DEF_TESTER) INSTANCE_TYPE_CHECKERS(DEF_TESTER)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment