// 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/compiler/graph-reducer.h" #include "src/globals.h" #include "src/machine-type.h" #include "src/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 {} const char* reducer_name() const override { return "LoadElimination"; } Reduction Reduce(Node* node) final; private: static const size_t kMaxTrackedChecks = 8; // Abstract state to approximate the current state of checks that are // only invalidated by calls, i.e. array buffer neutering checks, along // the effect paths through the graph. class AbstractChecks final : public ZoneObject { public: explicit AbstractChecks(Zone* zone) { for (size_t i = 0; i < arraysize(nodes_); ++i) { nodes_[i] = nullptr; } } AbstractChecks(Node* node, Zone* zone) : AbstractChecks(zone) { nodes_[next_index_++] = node; } AbstractChecks const* Extend(Node* node, Zone* zone) const { AbstractChecks* that = new (zone) AbstractChecks(*this); that->nodes_[that->next_index_] = node; that->next_index_ = (that->next_index_ + 1) % arraysize(nodes_); return that; } Node* Lookup(Node* node) const; bool Equals(AbstractChecks const* that) const; AbstractChecks const* Merge(AbstractChecks const* that, Zone* zone) const; void Print() const; private: Node* nodes_[kMaxTrackedChecks]; size_t next_index_ = 0; }; 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 = new (zone) 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() {} 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; // 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, Node* value, MaybeHandle name, Zone* zone) : info_for_node_(zone) { info_for_node_.insert(std::make_pair(object, Field(value, name))); } AbstractField const* Extend(Node* object, Node* value, MaybeHandle name, Zone* zone) const { AbstractField* that = new (zone) AbstractField(zone); that->info_for_node_ = this->info_for_node_; that->info_for_node_.insert(std::make_pair(object, Field(value, name))); return that; } Node* Lookup(Node* object) const; AbstractField const* Kill(const AliasStateInfo& alias_info, MaybeHandle 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 = new (zone) AbstractField(zone); for (auto this_it : this->info_for_node_) { Node* this_object = this_it.first; Field 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: struct Field { Field() {} Field(Node* value, MaybeHandle name) : value(value), name(name) {} bool operator==(const Field& other) const { return value == other.value && name.address() == other.name.address(); } Node* value = nullptr; MaybeHandle name; }; ZoneMap 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 maps, Zone* zone); AbstractMaps const* Extend(Node* object, ZoneHandleSet maps, Zone* zone) const; bool Lookup(Node* object, ZoneHandleSet* 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> info_for_node_; }; class AbstractState final : public ZoneObject { public: AbstractState() { for (size_t i = 0; i < arraysize(fields_); ++i) { fields_[i] = nullptr; } } bool Equals(AbstractState const* that) const; void Merge(AbstractState const* that, Zone* zone); AbstractState const* SetMaps(Node* object, ZoneHandleSet 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* object_maps) const; AbstractState const* AddField(Node* object, size_t index, Node* value, MaybeHandle name, Zone* zone) const; AbstractState const* KillField(const AliasStateInfo& alias_info, size_t index, MaybeHandle name, Zone* zone) const; AbstractState const* KillField(Node* object, size_t index, MaybeHandle name, Zone* zone) const; AbstractState const* KillFields(Node* object, MaybeHandle name, Zone* zone) const; Node* LookupField(Node* object, size_t index) 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; AbstractState const* AddCheck(Node* node, Zone* zone) const; Node* LookupCheck(Node* node) const; void Print() const; private: AbstractChecks const* checks_ = nullptr; AbstractElements const* elements_ = nullptr; AbstractField const* fields_[kMaxTrackedFields]; 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 info_for_node_; }; Reduction ReduceArrayBufferWasNeutered(Node* 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); Reduction ReduceStoreField(Node* node); 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* UpdateStateForPhi(AbstractState const* state, Node* effect_phi, Node* phi); static int FieldIndexOf(int offset); static int FieldIndexOf(FieldAccess const& access); CommonOperatorBuilder* common() const; AbstractState const* empty_state() const { return &empty_state_; } Isolate* isolate() const; Factory* factory() const; Graph* graph() const; JSGraph* jsgraph() const { return jsgraph_; } Zone* zone() const { return node_states_.zone(); } AbstractState const empty_state_; AbstractStateForEffectNodes node_states_; JSGraph* const jsgraph_; DISALLOW_COPY_AND_ASSIGN(LoadElimination); }; } // namespace compiler } // namespace internal } // namespace v8 #endif // V8_COMPILER_LOAD_ELIMINATION_H_