| // Copyright 2016 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_COMPILER_LOAD_ELIMINATION_H_ |
| #define V8_COMPILER_LOAD_ELIMINATION_H_ |
| |
| #include "src/base/compiler-specific.h" |
| #include "src/codegen/machine-type.h" |
| #include "src/common/globals.h" |
| #include "src/compiler/graph-reducer.h" |
| #include "src/compiler/simplified-operator.h" |
| #include "src/handles/maybe-handles.h" |
| #include "src/zone/zone-handle-set.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // Forward declarations. |
| class Factory; |
| |
| namespace compiler { |
| |
| // Forward declarations. |
| class CommonOperatorBuilder; |
| struct FieldAccess; |
| class Graph; |
| class JSGraph; |
| |
| class V8_EXPORT_PRIVATE LoadElimination final |
| : public NON_EXPORTED_BASE(AdvancedReducer) { |
| public: |
| LoadElimination(Editor* editor, JSGraph* jsgraph, Zone* zone) |
| : AdvancedReducer(editor), node_states_(zone), jsgraph_(jsgraph) {} |
| ~LoadElimination() final = default; |
| LoadElimination(const LoadElimination&) = delete; |
| LoadElimination& operator=(const LoadElimination&) = delete; |
| |
| const char* reducer_name() const override { return "LoadElimination"; } |
| |
| Reduction Reduce(Node* node) final; |
| |
| private: |
| static const size_t kMaxTrackedElements = 8; |
| |
| // Abstract state to approximate the current state of an element along the |
| // effect paths through the graph. |
| class AbstractElements final : public ZoneObject { |
| public: |
| explicit AbstractElements(Zone* zone) { |
| for (size_t i = 0; i < arraysize(elements_); ++i) { |
| elements_[i] = Element(); |
| } |
| } |
| AbstractElements(Node* object, Node* index, Node* value, |
| MachineRepresentation representation, Zone* zone) |
| : AbstractElements(zone) { |
| elements_[next_index_++] = Element(object, index, value, representation); |
| } |
| |
| AbstractElements const* Extend(Node* object, Node* index, Node* value, |
| MachineRepresentation representation, |
| Zone* zone) const { |
| AbstractElements* that = zone->New<AbstractElements>(*this); |
| that->elements_[that->next_index_] = |
| Element(object, index, value, representation); |
| that->next_index_ = (that->next_index_ + 1) % arraysize(elements_); |
| return that; |
| } |
| Node* Lookup(Node* object, Node* index, |
| MachineRepresentation representation) const; |
| AbstractElements const* Kill(Node* object, Node* index, Zone* zone) const; |
| bool Equals(AbstractElements const* that) const; |
| AbstractElements const* Merge(AbstractElements const* that, |
| Zone* zone) const; |
| |
| void Print() const; |
| |
| private: |
| struct Element { |
| Element() = default; |
| Element(Node* object, Node* index, Node* value, |
| MachineRepresentation representation) |
| : object(object), |
| index(index), |
| value(value), |
| representation(representation) {} |
| |
| Node* object = nullptr; |
| Node* index = nullptr; |
| Node* value = nullptr; |
| MachineRepresentation representation = MachineRepresentation::kNone; |
| }; |
| |
| Element elements_[kMaxTrackedElements]; |
| size_t next_index_ = 0; |
| }; |
| |
| // Information we use to resolve object aliasing. Currently, we consider |
| // object not aliased if they have different maps or if the nodes may |
| // not alias. |
| class AliasStateInfo; |
| |
| struct FieldInfo { |
| FieldInfo() = default; |
| FieldInfo(Node* value, MachineRepresentation representation, |
| MaybeHandle<Name> name = {}, |
| ConstFieldInfo const_field_info = ConstFieldInfo::None()) |
| : value(value), |
| representation(representation), |
| name(name), |
| const_field_info(const_field_info) {} |
| |
| bool operator==(const FieldInfo& other) const { |
| return value == other.value && representation == other.representation && |
| name.address() == other.name.address() && |
| const_field_info == other.const_field_info; |
| } |
| bool operator!=(const FieldInfo& other) const { return !(*this == other); } |
| |
| Node* value = nullptr; |
| MachineRepresentation representation = MachineRepresentation::kNone; |
| MaybeHandle<Name> name; |
| ConstFieldInfo const_field_info; |
| }; |
| |
| // Abstract state to approximate the current state of a certain field along |
| // the effect paths through the graph. |
| class AbstractField final : public ZoneObject { |
| public: |
| explicit AbstractField(Zone* zone) : info_for_node_(zone) {} |
| AbstractField(Node* object, FieldInfo info, Zone* zone) |
| : info_for_node_(zone) { |
| info_for_node_.insert(std::make_pair(object, info)); |
| } |
| |
| AbstractField const* Extend(Node* object, FieldInfo info, |
| Zone* zone) const { |
| AbstractField* that = zone->New<AbstractField>(zone); |
| that->info_for_node_ = this->info_for_node_; |
| that->info_for_node_[object] = info; |
| return that; |
| } |
| FieldInfo const* Lookup(Node* object) const; |
| AbstractField const* KillConst(Node* object, Zone* zone) const; |
| AbstractField const* Kill(const AliasStateInfo& alias_info, |
| MaybeHandle<Name> name, Zone* zone) const; |
| bool Equals(AbstractField const* that) const { |
| return this == that || this->info_for_node_ == that->info_for_node_; |
| } |
| AbstractField const* Merge(AbstractField const* that, Zone* zone) const { |
| if (this->Equals(that)) return this; |
| AbstractField* copy = zone->New<AbstractField>(zone); |
| for (auto this_it : this->info_for_node_) { |
| Node* this_object = this_it.first; |
| FieldInfo this_second = this_it.second; |
| if (this_object->IsDead()) continue; |
| auto that_it = that->info_for_node_.find(this_object); |
| if (that_it != that->info_for_node_.end() && |
| that_it->second == this_second) { |
| copy->info_for_node_.insert(this_it); |
| } |
| } |
| return copy; |
| } |
| |
| void Print() const; |
| |
| private: |
| ZoneMap<Node*, FieldInfo> info_for_node_; |
| }; |
| |
| static size_t const kMaxTrackedFields = 32; |
| |
| // Abstract state to approximate the current map of an object along the |
| // effect paths through the graph. |
| class AbstractMaps final : public ZoneObject { |
| public: |
| explicit AbstractMaps(Zone* zone); |
| AbstractMaps(Node* object, ZoneHandleSet<Map> maps, Zone* zone); |
| |
| AbstractMaps const* Extend(Node* object, ZoneHandleSet<Map> maps, |
| Zone* zone) const; |
| bool Lookup(Node* object, ZoneHandleSet<Map>* object_maps) const; |
| AbstractMaps const* Kill(const AliasStateInfo& alias_info, |
| Zone* zone) const; |
| bool Equals(AbstractMaps const* that) const { |
| return this == that || this->info_for_node_ == that->info_for_node_; |
| } |
| AbstractMaps const* Merge(AbstractMaps const* that, Zone* zone) const; |
| |
| void Print() const; |
| |
| private: |
| ZoneMap<Node*, ZoneHandleSet<Map>> info_for_node_; |
| }; |
| |
| class IndexRange { |
| public: |
| IndexRange(int begin, int size) : begin_(begin), end_(begin + size) { |
| DCHECK_LE(0, begin); |
| DCHECK_LE(1, size); |
| if (end_ > static_cast<int>(kMaxTrackedFields)) { |
| *this = IndexRange::Invalid(); |
| } |
| } |
| static IndexRange Invalid() { return IndexRange(); } |
| |
| bool operator==(const IndexRange& other) { |
| return begin_ == other.begin_ && end_ == other.end_; |
| } |
| bool operator!=(const IndexRange& other) { return !(*this == other); } |
| |
| struct Iterator { |
| int i; |
| int operator*() { return i; } |
| void operator++() { ++i; } |
| bool operator!=(Iterator other) { return i != other.i; } |
| }; |
| |
| Iterator begin() { return {begin_}; } |
| Iterator end() { return {end_}; } |
| |
| private: |
| int begin_; |
| int end_; |
| |
| IndexRange() : begin_(-1), end_(-1) {} |
| }; |
| |
| class AbstractState final : public ZoneObject { |
| public: |
| bool Equals(AbstractState const* that) const; |
| void Merge(AbstractState const* that, Zone* zone); |
| |
| AbstractState const* SetMaps(Node* object, ZoneHandleSet<Map> maps, |
| Zone* zone) const; |
| AbstractState const* KillMaps(Node* object, Zone* zone) const; |
| AbstractState const* KillMaps(const AliasStateInfo& alias_info, |
| Zone* zone) const; |
| bool LookupMaps(Node* object, ZoneHandleSet<Map>* object_maps) const; |
| |
| AbstractState const* AddField(Node* object, IndexRange index, |
| FieldInfo info, Zone* zone) const; |
| AbstractState const* KillConstField(Node* object, IndexRange index_range, |
| Zone* zone) const; |
| AbstractState const* KillField(const AliasStateInfo& alias_info, |
| IndexRange index, MaybeHandle<Name> name, |
| Zone* zone) const; |
| AbstractState const* KillField(Node* object, IndexRange index, |
| MaybeHandle<Name> name, Zone* zone) const; |
| AbstractState const* KillFields(Node* object, MaybeHandle<Name> name, |
| Zone* zone) const; |
| AbstractState const* KillAll(Zone* zone) const; |
| FieldInfo const* LookupField(Node* object, IndexRange index, |
| ConstFieldInfo const_field_info) const; |
| |
| AbstractState const* AddElement(Node* object, Node* index, Node* value, |
| MachineRepresentation representation, |
| Zone* zone) const; |
| AbstractState const* KillElement(Node* object, Node* index, |
| Zone* zone) const; |
| Node* LookupElement(Node* object, Node* index, |
| MachineRepresentation representation) const; |
| |
| void Print() const; |
| |
| static AbstractState const* empty_state() { return &empty_state_; } |
| |
| private: |
| static AbstractState const empty_state_; |
| |
| using AbstractFields = std::array<AbstractField const*, kMaxTrackedFields>; |
| |
| bool FieldsEquals(AbstractFields const& this_fields, |
| AbstractFields const& that_fields) const; |
| void FieldsMerge(AbstractFields* this_fields, |
| AbstractFields const& that_fields, Zone* zone); |
| |
| AbstractElements const* elements_ = nullptr; |
| AbstractFields fields_{}; |
| AbstractFields const_fields_{}; |
| AbstractMaps const* maps_ = nullptr; |
| }; |
| |
| class AbstractStateForEffectNodes final : public ZoneObject { |
| public: |
| explicit AbstractStateForEffectNodes(Zone* zone) : info_for_node_(zone) {} |
| AbstractState const* Get(Node* node) const; |
| void Set(Node* node, AbstractState const* state); |
| |
| Zone* zone() const { return info_for_node_.get_allocator().zone(); } |
| |
| private: |
| ZoneVector<AbstractState const*> info_for_node_; |
| }; |
| |
| Reduction ReduceCheckMaps(Node* node); |
| Reduction ReduceCompareMaps(Node* node); |
| Reduction ReduceMapGuard(Node* node); |
| Reduction ReduceEnsureWritableFastElements(Node* node); |
| Reduction ReduceMaybeGrowFastElements(Node* node); |
| Reduction ReduceTransitionElementsKind(Node* node); |
| Reduction ReduceLoadField(Node* node, FieldAccess const& access); |
| Reduction ReduceStoreField(Node* node, FieldAccess const& access); |
| Reduction ReduceLoadElement(Node* node); |
| Reduction ReduceStoreElement(Node* node); |
| Reduction ReduceTransitionAndStoreElement(Node* node); |
| Reduction ReduceStoreTypedElement(Node* node); |
| Reduction ReduceEffectPhi(Node* node); |
| Reduction ReduceStart(Node* node); |
| Reduction ReduceOtherNode(Node* node); |
| |
| Reduction UpdateState(Node* node, AbstractState const* state); |
| |
| AbstractState const* ComputeLoopState(Node* node, |
| AbstractState const* state) const; |
| AbstractState const* ComputeLoopStateForStoreField( |
| Node* current, LoadElimination::AbstractState const* state, |
| FieldAccess const& access) const; |
| AbstractState const* UpdateStateForPhi(AbstractState const* state, |
| Node* effect_phi, Node* phi); |
| |
| static IndexRange FieldIndexOf(int offset, int representation_size); |
| static IndexRange FieldIndexOf(FieldAccess const& access); |
| |
| static AbstractState const* empty_state() { |
| return AbstractState::empty_state(); |
| } |
| |
| CommonOperatorBuilder* common() const; |
| Isolate* isolate() const; |
| Factory* factory() const; |
| Graph* graph() const; |
| JSGraph* jsgraph() const { return jsgraph_; } |
| Zone* zone() const { return node_states_.zone(); } |
| |
| AbstractStateForEffectNodes node_states_; |
| JSGraph* const jsgraph_; |
| }; |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_COMPILER_LOAD_ELIMINATION_H_ |