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,
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 ( )
Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
......@@ -4342,18 +4316,11 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
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;
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Try to determine the {receiver} map(s).
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(broker(), receiver, effect,
......@@ -4362,18 +4329,15 @@ Reduction JSCallReducer::ReduceArrayPrototypePush(Node* node) {
DCHECK_NE(0, receiver_maps.size());
ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
receiver_map.SerializePrototype();
if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
return NoChange();
if (!receiver_map.supports_fast_array_resize()) return NoChange();
if (!UnionElementsKindUptoPackedness(&kind, receiver_map.elements_kind()))
return NoChange();
}
// Install code dependencies on the {receiver} global array protector cell.
dependencies()->DependOnProtector(no_elements_protector);
dependencies()->DependOnProtector(
PropertyCellRef(broker(), factory()->no_elements_protector()));
// If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps.
......@@ -4461,12 +4425,6 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
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* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
......@@ -4481,9 +4439,7 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
receiver_map.SerializePrototype();
if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
return NoChange();
if (!receiver_map.supports_fast_array_resize()) return NoChange();
// TODO(turbofan): Extend this to also handle fast holey double elements
// once we got the hole NaN mess sorted out in TurboFan/V8.
if (receiver_map.elements_kind() == HOLEY_DOUBLE_ELEMENTS)
......@@ -4492,8 +4448,8 @@ Reduction JSCallReducer::ReduceArrayPrototypePop(Node* node) {
return NoChange();
}
// Install code dependencies on the {receiver} global array protector cell.
dependencies()->DependOnProtector(no_elements_protector);
dependencies()->DependOnProtector(
PropertyCellRef(broker(), factory()->no_elements_protector()));
// If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps.
......@@ -4583,12 +4539,6 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
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* receiver = NodeProperties::GetValueInput(node, 1);
Node* context = NodeProperties::GetContextInput(node);
......@@ -4606,9 +4556,7 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
ElementsKind kind = receiver_maps[0]->elements_kind();
for (Handle<Map> map : receiver_maps) {
MapRef receiver_map(broker(), map);
receiver_map.SerializePrototype();
if (!CanInlineArrayResizeOperation(isolate(), receiver_map))
return NoChange();
if (!receiver_map.supports_fast_array_resize()) return NoChange();
// TODO(turbofan): Extend this to also handle fast holey double elements
// once we got the hole NaN mess sorted out in TurboFan/V8.
if (receiver_map.elements_kind() == HOLEY_DOUBLE_ELEMENTS)
......@@ -4617,8 +4565,8 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
return NoChange();
}
// Install code dependencies on the {receiver} global array protector cell.
dependencies()->DependOnProtector(no_elements_protector);
dependencies()->DependOnProtector(
PropertyCellRef(broker(), factory()->no_elements_protector()));
// If the {receiver_maps} information is not reliable, we need
// to check that the {receiver} still has one of these maps.
......
......@@ -649,6 +649,9 @@ class MapData : public HeapObjectData {
int constructor_function_index() const { return constructor_function_index_; }
int NextFreePropertyIndex() const { return next_free_property_index_; }
int UnusedPropertyFields() const { return unused_property_fields_; }
bool supports_fast_array_resize() const {
return supports_fast_array_resize_;
}
// Extra information.
......@@ -691,6 +694,7 @@ class MapData : public HeapObjectData {
int const constructor_function_index_;
int const next_free_property_index_;
int const unused_property_fields_;
bool const supports_fast_array_resize_;
bool serialized_elements_kind_generalizations_ = false;
ZoneVector<MapData*> elements_kind_generalizations_;
......@@ -752,6 +756,28 @@ HeapObjectData::HeapObjectData(JSHeapBroker* broker, ObjectData** storage,
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)
: HeapObjectData(broker, storage, object),
instance_type_(object->instance_type()),
......@@ -773,6 +799,8 @@ MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object)
: Map::kNoConstructorFunctionIndex),
next_free_property_index_(object->NextFreePropertyIndex()),
unused_property_fields_(object->UnusedPropertyFields()),
supports_fast_array_resize_(
SupportsFastArrayResize(broker->isolate(), object)),
elements_kind_generalizations_(broker->zone()) {}
JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
......@@ -1819,6 +1847,15 @@ base::Optional<MapRef> MapRef::AsElementsKind(ElementsKind kind) const {
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 {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
......
......@@ -433,6 +433,7 @@ class MapRef : public HeapObjectRef {
bool is_undetectable() const;
bool is_callable() const;
bool has_hidden_prototype() const;
bool supports_fast_array_resize() const;
#define DEF_TESTER(Type, ...) bool Is##Type##Map() const;
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