diff options
Diffstat (limited to 'src/compiler/load-elimination.cc')
-rw-r--r-- | src/compiler/load-elimination.cc | 276 |
1 files changed, 200 insertions, 76 deletions
diff --git a/src/compiler/load-elimination.cc b/src/compiler/load-elimination.cc index e50ebe19..10140e14 100644 --- a/src/compiler/load-elimination.cc +++ b/src/compiler/load-elimination.cc @@ -8,6 +8,8 @@ #include "src/compiler/js-graph.h" #include "src/compiler/node-properties.h" #include "src/compiler/simplified-operator.h" +#include "src/factory.h" +#include "src/objects-inl.h" namespace v8 { namespace internal { @@ -320,6 +322,42 @@ void LoadElimination::AbstractField::Print() const { } } +bool LoadElimination::AbstractMaps::Lookup( + Node* object, ZoneHandleSet<Map>* object_maps) const { + for (auto pair : info_for_node_) { + if (MustAlias(object, pair.first)) { + *object_maps = pair.second; + return true; + } + } + return false; +} + +LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Kill( + Node* object, Zone* zone) const { + for (auto pair : this->info_for_node_) { + if (MayAlias(object, pair.first)) { + AbstractMaps* that = new (zone) AbstractMaps(zone); + for (auto pair : this->info_for_node_) { + if (!MayAlias(object, pair.first)) that->info_for_node_.insert(pair); + } + return that; + } + } + return this; +} + +void LoadElimination::AbstractMaps::Print() const { + for (auto pair : info_for_node_) { + PrintF(" #%d:%s\n", pair.first->id(), pair.first->op()->mnemonic()); + OFStream os(stdout); + ZoneHandleSet<Map> const& maps = pair.second; + for (size_t i = 0; i < maps.size(); ++i) { + os << " - " << Brief(*maps[i]) << "\n"; + } + } +} + bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { if (this->checks_) { if (!that->checks_ || !that->checks_->Equals(this->checks_)) { @@ -344,6 +382,13 @@ bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { return false; } } + if (this->maps_) { + if (!that->maps_ || !that->maps_->Equals(this->maps_)) { + return false; + } + } else if (that->maps_) { + return false; + } return true; } @@ -372,6 +417,11 @@ void LoadElimination::AbstractState::Merge(AbstractState const* that, } } } + + // Merge the information we have about the maps. + if (this->maps_) { + this->maps_ = that->maps_ ? that->maps_->Merge(this->maps_, zone) : nullptr; + } } Node* LoadElimination::AbstractState::LookupCheck(Node* node) const { @@ -389,6 +439,35 @@ LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck( return that; } +bool LoadElimination::AbstractState::LookupMaps( + Node* object, ZoneHandleSet<Map>* object_map) const { + return this->maps_ && this->maps_->Lookup(object, object_map); +} + +LoadElimination::AbstractState const* LoadElimination::AbstractState::AddMaps( + Node* object, ZoneHandleSet<Map> maps, Zone* zone) const { + AbstractState* that = new (zone) AbstractState(*this); + if (that->maps_) { + that->maps_ = that->maps_->Extend(object, maps, zone); + } else { + that->maps_ = new (zone) AbstractMaps(object, maps, zone); + } + return that; +} + +LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps( + Node* object, Zone* zone) const { + if (this->maps_) { + AbstractMaps const* that_maps = this->maps_->Kill(object, zone); + if (this->maps_ != that_maps) { + AbstractState* that = new (zone) AbstractState(*this); + that->maps_ = that_maps; + return that; + } + } + return this; +} + Node* LoadElimination::AbstractState::LookupElement(Node* object, Node* index) const { if (this->elements_) { @@ -456,7 +535,7 @@ LoadElimination::AbstractState::KillFields(Node* object, Zone* zone) const { AbstractField const* that_field = this_field->Kill(object, zone); if (that_field != this_field) { AbstractState* that = new (zone) AbstractState(*this); - that->fields_[i] = this_field; + that->fields_[i] = that_field; while (++i < arraysize(fields_)) { if (this->fields_[i] != nullptr) { that->fields_[i] = this->fields_[i]->Kill(object, zone); @@ -481,6 +560,10 @@ void LoadElimination::AbstractState::Print() const { PrintF(" checks:\n"); checks_->Print(); } + if (maps_) { + PrintF(" maps:\n"); + maps_->Print(); + } if (elements_) { PrintF(" elements:\n"); elements_->Print(); @@ -520,23 +603,18 @@ Reduction LoadElimination::ReduceArrayBufferWasNeutered(Node* node) { } Reduction LoadElimination::ReduceCheckMaps(Node* node) { + ZoneHandleSet<Map> const maps = CheckMapsParametersOf(node->op()).maps(); Node* const object = NodeProperties::GetValueInput(node, 0); Node* const effect = NodeProperties::GetEffectInput(node); AbstractState const* state = node_states_.Get(effect); if (state == nullptr) return NoChange(); - int const map_input_count = node->op()->ValueInputCount() - 1; - if (Node* const object_map = - state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { - for (int i = 0; i < map_input_count; ++i) { - Node* map = NodeProperties::GetValueInput(node, 1 + i); - if (map == object_map) return Replace(effect); - } - } - if (map_input_count == 1) { - Node* const map0 = NodeProperties::GetValueInput(node, 1); - state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), map0, - zone()); + ZoneHandleSet<Map> object_maps; + if (state->LookupMaps(object, &object_maps)) { + if (maps.contains(object_maps)) return Replace(effect); + state = state->KillMaps(object, zone()); + // TODO(turbofan): Compute the intersection. } + state = state->AddMaps(object, maps, zone()); return UpdateState(node, state); } @@ -546,18 +624,16 @@ Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) { Node* const effect = NodeProperties::GetEffectInput(node); AbstractState const* state = node_states_.Get(effect); if (state == nullptr) return NoChange(); - Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); - if (Node* const elements_map = - state->LookupField(elements, FieldIndexOf(HeapObject::kMapOffset))) { // Check if the {elements} already have the fixed array map. - if (elements_map == fixed_array_map) { - ReplaceWithValue(node, elements, effect); - return Replace(elements); - } + ZoneHandleSet<Map> elements_maps; + ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map()); + if (state->LookupMaps(elements, &elements_maps) && + fixed_array_maps.contains(elements_maps)) { + ReplaceWithValue(node, elements, effect); + return Replace(elements); } // We know that the resulting elements have the fixed array map. - state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), - fixed_array_map, zone()); + state = state->AddMaps(node, fixed_array_maps, zone()); // Kill the previous elements on {object}. state = state->KillField(object, FieldIndexOf(JSObject::kElementsOffset), zone()); @@ -575,14 +651,12 @@ Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { if (state == nullptr) return NoChange(); if (flags & GrowFastElementsFlag::kDoubleElements) { // We know that the resulting elements have the fixed double array map. - Node* fixed_double_array_map = jsgraph()->FixedDoubleArrayMapConstant(); - state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), - fixed_double_array_map, zone()); + state = state->AddMaps( + node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone()); } else { // We know that the resulting elements have the fixed array map. - Node* fixed_array_map = jsgraph()->FixedArrayMapConstant(); - state = state->AddField(node, FieldIndexOf(HeapObject::kMapOffset), - fixed_array_map, zone()); + state = state->AddMaps( + node, ZoneHandleSet<Map>(factory()->fixed_array_map()), zone()); } if (flags & GrowFastElementsFlag::kArrayObject) { // Kill the previous Array::length on {object}. @@ -599,31 +673,30 @@ Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) { } Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) { + ElementsTransition transition = ElementsTransitionOf(node->op()); Node* const object = NodeProperties::GetValueInput(node, 0); - Node* const source_map = NodeProperties::GetValueInput(node, 1); - Node* const target_map = NodeProperties::GetValueInput(node, 2); + Handle<Map> source_map(transition.source()); + Handle<Map> target_map(transition.target()); Node* const effect = NodeProperties::GetEffectInput(node); AbstractState const* state = node_states_.Get(effect); if (state == nullptr) return NoChange(); - if (Node* const object_map = - state->LookupField(object, FieldIndexOf(HeapObject::kMapOffset))) { - if (target_map == object_map) { + ZoneHandleSet<Map> object_maps; + if (state->LookupMaps(object, &object_maps)) { + if (ZoneHandleSet<Map>(target_map).contains(object_maps)) { // The {object} already has the {target_map}, so this TransitionElements // {node} is fully redundant (independent of what {source_map} is). return Replace(effect); } - state = - state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); - if (source_map == object_map) { - state = state->AddField(object, FieldIndexOf(HeapObject::kMapOffset), - target_map, zone()); + if (object_maps.contains(ZoneHandleSet<Map>(source_map))) { + object_maps.remove(source_map, zone()); + object_maps.insert(target_map, zone()); + state = state->KillMaps(object, zone()); + state = state->AddMaps(object, object_maps, zone()); } } else { - state = - state->KillField(object, FieldIndexOf(HeapObject::kMapOffset), zone()); + state = state->KillMaps(object, zone()); } - ElementsTransition transition = ElementsTransitionOf(node->op()); - switch (transition) { + switch (transition.mode()) { case ElementsTransition::kFastTransition: break; case ElementsTransition::kSlowTransition: @@ -642,23 +715,40 @@ Reduction LoadElimination::ReduceLoadField(Node* node) { Node* const control = NodeProperties::GetControlInput(node); AbstractState const* state = node_states_.Get(effect); if (state == nullptr) return NoChange(); - int field_index = FieldIndexOf(access); - if (field_index >= 0) { - if (Node* replacement = state->LookupField(object, field_index)) { - // Make sure we don't resurrect dead {replacement} nodes. - if (!replacement->IsDead()) { - // We might need to guard the {replacement} if the type of the - // {node} is more precise than the type of the {replacement}. - Type* const node_type = NodeProperties::GetType(node); - if (!NodeProperties::GetType(replacement)->Is(node_type)) { - replacement = graph()->NewNode(common()->TypeGuard(node_type), - replacement, control); + if (access.offset == HeapObject::kMapOffset && + access.base_is_tagged == kTaggedBase) { + DCHECK(IsAnyTagged(access.machine_type.representation())); + ZoneHandleSet<Map> object_maps; + if (state->LookupMaps(object, &object_maps) && object_maps.size() == 1) { + Node* value = jsgraph()->HeapConstant(object_maps[0]); + NodeProperties::SetType(value, Type::OtherInternal()); + ReplaceWithValue(node, value, effect); + return Replace(value); + } + } else { + int field_index = FieldIndexOf(access); + if (field_index >= 0) { + if (Node* replacement = state->LookupField(object, field_index)) { + // Make sure we don't resurrect dead {replacement} nodes. + if (!replacement->IsDead()) { + // We might need to guard the {replacement} if the type of the + // {node} is more precise than the type of the {replacement}. + Type* const node_type = NodeProperties::GetType(node); + if (!NodeProperties::GetType(replacement)->Is(node_type)) { + replacement = graph()->NewNode(common()->TypeGuard(node_type), + replacement, control); + NodeProperties::SetType(replacement, node_type); + } + ReplaceWithValue(node, replacement, effect); + return Replace(replacement); } - ReplaceWithValue(node, replacement, effect); - return Replace(replacement); } + state = state->AddField(object, field_index, node, zone()); } - state = state->AddField(object, field_index, node, zone()); + } + Handle<Map> field_map; + if (access.map.ToHandle(&field_map)) { + state = state->AddMaps(node, ZoneHandleSet<Map>(field_map), zone()); } return UpdateState(node, state); } @@ -670,19 +760,33 @@ Reduction LoadElimination::ReduceStoreField(Node* node) { Node* const effect = NodeProperties::GetEffectInput(node); AbstractState const* state = node_states_.Get(effect); if (state == nullptr) return NoChange(); - int field_index = FieldIndexOf(access); - if (field_index >= 0) { - Node* const old_value = state->LookupField(object, field_index); - if (old_value == new_value) { - // This store is fully redundant. - return Replace(effect); + if (access.offset == HeapObject::kMapOffset && + access.base_is_tagged == kTaggedBase) { + DCHECK(IsAnyTagged(access.machine_type.representation())); + // Kill all potential knowledge about the {object}s map. + state = state->KillMaps(object, zone()); + Type* const new_value_type = NodeProperties::GetType(new_value); + if (new_value_type->IsHeapConstant()) { + // Record the new {object} map information. + ZoneHandleSet<Map> object_maps( + Handle<Map>::cast(new_value_type->AsHeapConstant()->Value())); + state = state->AddMaps(object, object_maps, zone()); } - // Kill all potentially aliasing fields and record the new value. - state = state->KillField(object, field_index, zone()); - state = state->AddField(object, field_index, new_value, zone()); } else { - // Unsupported StoreField operator. - state = state->KillFields(object, zone()); + int field_index = FieldIndexOf(access); + if (field_index >= 0) { + Node* const old_value = state->LookupField(object, field_index); + if (old_value == new_value) { + // This store is fully redundant. + return Replace(effect); + } + // Kill all potentially aliasing fields and record the new value. + state = state->KillField(object, field_index, zone()); + state = state->AddField(object, field_index, new_value, zone()); + } else { + // Unsupported StoreField operator. + state = state->KillFields(object, zone()); + } } return UpdateState(node, state); } @@ -703,6 +807,7 @@ Reduction LoadElimination::ReduceLoadElement(Node* node) { if (!NodeProperties::GetType(replacement)->Is(node_type)) { replacement = graph()->NewNode(common()->TypeGuard(node_type), replacement, control); + NodeProperties::SetType(replacement, node_type); } ReplaceWithValue(node, replacement, effect); return Replace(replacement); @@ -730,6 +835,9 @@ Reduction LoadElimination::ReduceStoreElement(Node* node) { // Only record the new value if the store doesn't have an implicit truncation. switch (access.machine_type.representation()) { case MachineRepresentation::kNone: + case MachineRepresentation::kSimd1x4: + case MachineRepresentation::kSimd1x8: + case MachineRepresentation::kSimd1x16: case MachineRepresentation::kBit: UNREACHABLE(); break; @@ -865,21 +973,31 @@ LoadElimination::AbstractState const* LoadElimination::ComputeLoopState( break; } case IrOpcode::kTransitionElementsKind: { + ElementsTransition transition = ElementsTransitionOf(current->op()); Node* const object = NodeProperties::GetValueInput(current, 0); - state = state->KillField( - object, FieldIndexOf(HeapObject::kMapOffset), zone()); - state = state->KillField( - object, FieldIndexOf(JSObject::kElementsOffset), zone()); + ZoneHandleSet<Map> object_maps; + if (!state->LookupMaps(object, &object_maps) || + !ZoneHandleSet<Map>(transition.target()) + .contains(object_maps)) { + state = state->KillMaps(object, zone()); + state = state->KillField( + object, FieldIndexOf(JSObject::kElementsOffset), zone()); + } break; } case IrOpcode::kStoreField: { FieldAccess const& access = FieldAccessOf(current->op()); Node* const object = NodeProperties::GetValueInput(current, 0); - int field_index = FieldIndexOf(access); - if (field_index < 0) { - state = state->KillFields(object, zone()); + if (access.offset == HeapObject::kMapOffset) { + // Invalidate what we know about the {object}s map. + state = state->KillMaps(object, zone()); } else { - state = state->KillField(object, field_index, zone()); + int field_index = FieldIndexOf(access); + if (field_index < 0) { + state = state->KillFields(object, zone()); + } else { + state = state->KillField(object, field_index, zone()); + } } break; } @@ -911,7 +1029,8 @@ int LoadElimination::FieldIndexOf(int offset) { DCHECK_EQ(0, offset % kPointerSize); int field_index = offset / kPointerSize; if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; - return field_index; + DCHECK_LT(0, field_index); + return field_index - 1; } // static @@ -921,6 +1040,9 @@ int LoadElimination::FieldIndexOf(FieldAccess const& access) { case MachineRepresentation::kNone: case MachineRepresentation::kBit: case MachineRepresentation::kSimd128: + case MachineRepresentation::kSimd1x4: + case MachineRepresentation::kSimd1x8: + case MachineRepresentation::kSimd1x16: UNREACHABLE(); break; case MachineRepresentation::kWord32: @@ -957,6 +1079,8 @@ CommonOperatorBuilder* LoadElimination::common() const { Graph* LoadElimination::graph() const { return jsgraph()->graph(); } +Factory* LoadElimination::factory() const { return jsgraph()->factory(); } + } // namespace compiler } // namespace internal } // namespace v8 |