Home | History | Annotate | Download | only in compiler
      1 // Copyright 2016 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_COMPILER_LOAD_ELIMINATION_H_
      6 #define V8_COMPILER_LOAD_ELIMINATION_H_
      7 
      8 #include "src/base/compiler-specific.h"
      9 #include "src/compiler/graph-reducer.h"
     10 #include "src/globals.h"
     11 #include "src/zone/zone-handle-set.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 // Forward declarations.
     17 class Factory;
     18 
     19 namespace compiler {
     20 
     21 // Foward declarations.
     22 class CommonOperatorBuilder;
     23 struct FieldAccess;
     24 class Graph;
     25 class JSGraph;
     26 
     27 class V8_EXPORT_PRIVATE LoadElimination final
     28     : public NON_EXPORTED_BASE(AdvancedReducer) {
     29  public:
     30   LoadElimination(Editor* editor, JSGraph* jsgraph, Zone* zone)
     31       : AdvancedReducer(editor), node_states_(zone), jsgraph_(jsgraph) {}
     32   ~LoadElimination() final {}
     33 
     34   Reduction Reduce(Node* node) final;
     35 
     36  private:
     37   static const size_t kMaxTrackedChecks = 8;
     38 
     39   // Abstract state to approximate the current state of checks that are
     40   // only invalidated by calls, i.e. array buffer neutering checks, along
     41   // the effect paths through the graph.
     42   class AbstractChecks final : public ZoneObject {
     43    public:
     44     explicit AbstractChecks(Zone* zone) {
     45       for (size_t i = 0; i < arraysize(nodes_); ++i) {
     46         nodes_[i] = nullptr;
     47       }
     48     }
     49     AbstractChecks(Node* node, Zone* zone) : AbstractChecks(zone) {
     50       nodes_[next_index_++] = node;
     51     }
     52 
     53     AbstractChecks const* Extend(Node* node, Zone* zone) const {
     54       AbstractChecks* that = new (zone) AbstractChecks(*this);
     55       that->nodes_[that->next_index_] = node;
     56       that->next_index_ = (that->next_index_ + 1) % arraysize(nodes_);
     57       return that;
     58     }
     59     Node* Lookup(Node* node) const;
     60     bool Equals(AbstractChecks const* that) const;
     61     AbstractChecks const* Merge(AbstractChecks const* that, Zone* zone) const;
     62 
     63     void Print() const;
     64 
     65    private:
     66     Node* nodes_[kMaxTrackedChecks];
     67     size_t next_index_ = 0;
     68   };
     69 
     70   static const size_t kMaxTrackedElements = 8;
     71 
     72   // Abstract state to approximate the current state of an element along the
     73   // effect paths through the graph.
     74   class AbstractElements final : public ZoneObject {
     75    public:
     76     explicit AbstractElements(Zone* zone) {
     77       for (size_t i = 0; i < arraysize(elements_); ++i) {
     78         elements_[i] = Element();
     79       }
     80     }
     81     AbstractElements(Node* object, Node* index, Node* value, Zone* zone)
     82         : AbstractElements(zone) {
     83       elements_[next_index_++] = Element(object, index, value);
     84     }
     85 
     86     AbstractElements const* Extend(Node* object, Node* index, Node* value,
     87                                    Zone* zone) const {
     88       AbstractElements* that = new (zone) AbstractElements(*this);
     89       that->elements_[that->next_index_] = Element(object, index, value);
     90       that->next_index_ = (that->next_index_ + 1) % arraysize(elements_);
     91       return that;
     92     }
     93     Node* Lookup(Node* object, Node* index) const;
     94     AbstractElements const* Kill(Node* object, Node* index, Zone* zone) const;
     95     bool Equals(AbstractElements const* that) const;
     96     AbstractElements const* Merge(AbstractElements const* that,
     97                                   Zone* zone) const;
     98 
     99     void Print() const;
    100 
    101    private:
    102     struct Element {
    103       Element() {}
    104       Element(Node* object, Node* index, Node* value)
    105           : object(object), index(index), value(value) {}
    106 
    107       Node* object = nullptr;
    108       Node* index = nullptr;
    109       Node* value = nullptr;
    110     };
    111 
    112     Element elements_[kMaxTrackedElements];
    113     size_t next_index_ = 0;
    114   };
    115 
    116   // Abstract state to approximate the current state of a certain field along
    117   // the effect paths through the graph.
    118   class AbstractField final : public ZoneObject {
    119    public:
    120     explicit AbstractField(Zone* zone) : info_for_node_(zone) {}
    121     AbstractField(Node* object, Node* value, Zone* zone)
    122         : info_for_node_(zone) {
    123       info_for_node_.insert(std::make_pair(object, value));
    124     }
    125 
    126     AbstractField const* Extend(Node* object, Node* value, Zone* zone) const {
    127       AbstractField* that = new (zone) AbstractField(zone);
    128       that->info_for_node_ = this->info_for_node_;
    129       that->info_for_node_.insert(std::make_pair(object, value));
    130       return that;
    131     }
    132     Node* Lookup(Node* object) const;
    133     AbstractField const* Kill(Node* object, Zone* zone) const;
    134     bool Equals(AbstractField const* that) const {
    135       return this == that || this->info_for_node_ == that->info_for_node_;
    136     }
    137     AbstractField const* Merge(AbstractField const* that, Zone* zone) const {
    138       if (this->Equals(that)) return this;
    139       AbstractField* copy = new (zone) AbstractField(zone);
    140       for (auto this_it : this->info_for_node_) {
    141         Node* this_object = this_it.first;
    142         Node* this_value = this_it.second;
    143         auto that_it = that->info_for_node_.find(this_object);
    144         if (that_it != that->info_for_node_.end() &&
    145             that_it->second == this_value) {
    146           copy->info_for_node_.insert(this_it);
    147         }
    148       }
    149       return copy;
    150     }
    151 
    152     void Print() const;
    153 
    154    private:
    155     ZoneMap<Node*, Node*> info_for_node_;
    156   };
    157 
    158   static size_t const kMaxTrackedFields = 32;
    159 
    160   // Abstract state to approximate the current map of an object along the
    161   // effect paths through the graph.
    162   class AbstractMaps final : public ZoneObject {
    163    public:
    164     explicit AbstractMaps(Zone* zone) : info_for_node_(zone) {}
    165     AbstractMaps(Node* object, ZoneHandleSet<Map> maps, Zone* zone)
    166         : info_for_node_(zone) {
    167       info_for_node_.insert(std::make_pair(object, maps));
    168     }
    169 
    170     AbstractMaps const* Extend(Node* object, ZoneHandleSet<Map> maps,
    171                                Zone* zone) const {
    172       AbstractMaps* that = new (zone) AbstractMaps(zone);
    173       that->info_for_node_ = this->info_for_node_;
    174       that->info_for_node_.insert(std::make_pair(object, maps));
    175       return that;
    176     }
    177     bool Lookup(Node* object, ZoneHandleSet<Map>* object_maps) const;
    178     AbstractMaps const* Kill(Node* object, Zone* zone) const;
    179     bool Equals(AbstractMaps const* that) const {
    180       return this == that || this->info_for_node_ == that->info_for_node_;
    181     }
    182     AbstractMaps const* Merge(AbstractMaps const* that, Zone* zone) const {
    183       if (this->Equals(that)) return this;
    184       AbstractMaps* copy = new (zone) AbstractMaps(zone);
    185       for (auto this_it : this->info_for_node_) {
    186         Node* this_object = this_it.first;
    187         ZoneHandleSet<Map> this_maps = this_it.second;
    188         auto that_it = that->info_for_node_.find(this_object);
    189         if (that_it != that->info_for_node_.end() &&
    190             that_it->second == this_maps) {
    191           copy->info_for_node_.insert(this_it);
    192         }
    193       }
    194       return copy;
    195     }
    196 
    197     void Print() const;
    198 
    199    private:
    200     ZoneMap<Node*, ZoneHandleSet<Map>> info_for_node_;
    201   };
    202 
    203   class AbstractState final : public ZoneObject {
    204    public:
    205     AbstractState() {
    206       for (size_t i = 0; i < arraysize(fields_); ++i) {
    207         fields_[i] = nullptr;
    208       }
    209     }
    210 
    211     bool Equals(AbstractState const* that) const;
    212     void Merge(AbstractState const* that, Zone* zone);
    213 
    214     AbstractState const* AddMaps(Node* object, ZoneHandleSet<Map> maps,
    215                                  Zone* zone) const;
    216     AbstractState const* KillMaps(Node* object, Zone* zone) const;
    217     bool LookupMaps(Node* object, ZoneHandleSet<Map>* object_maps) const;
    218 
    219     AbstractState const* AddField(Node* object, size_t index, Node* value,
    220                                   Zone* zone) const;
    221     AbstractState const* KillField(Node* object, size_t index,
    222                                    Zone* zone) const;
    223     AbstractState const* KillFields(Node* object, Zone* zone) const;
    224     Node* LookupField(Node* object, size_t index) const;
    225 
    226     AbstractState const* AddElement(Node* object, Node* index, Node* value,
    227                                     Zone* zone) const;
    228     AbstractState const* KillElement(Node* object, Node* index,
    229                                      Zone* zone) const;
    230     Node* LookupElement(Node* object, Node* index) const;
    231 
    232     AbstractState const* AddCheck(Node* node, Zone* zone) const;
    233     Node* LookupCheck(Node* node) const;
    234 
    235     void Print() const;
    236 
    237    private:
    238     AbstractChecks const* checks_ = nullptr;
    239     AbstractElements const* elements_ = nullptr;
    240     AbstractField const* fields_[kMaxTrackedFields];
    241     AbstractMaps const* maps_ = nullptr;
    242   };
    243 
    244   class AbstractStateForEffectNodes final : public ZoneObject {
    245    public:
    246     explicit AbstractStateForEffectNodes(Zone* zone) : info_for_node_(zone) {}
    247     AbstractState const* Get(Node* node) const;
    248     void Set(Node* node, AbstractState const* state);
    249 
    250     Zone* zone() const { return info_for_node_.get_allocator().zone(); }
    251 
    252    private:
    253     ZoneVector<AbstractState const*> info_for_node_;
    254   };
    255 
    256   Reduction ReduceArrayBufferWasNeutered(Node* node);
    257   Reduction ReduceCheckMaps(Node* node);
    258   Reduction ReduceEnsureWritableFastElements(Node* node);
    259   Reduction ReduceMaybeGrowFastElements(Node* node);
    260   Reduction ReduceTransitionElementsKind(Node* node);
    261   Reduction ReduceLoadField(Node* node);
    262   Reduction ReduceStoreField(Node* node);
    263   Reduction ReduceLoadElement(Node* node);
    264   Reduction ReduceStoreElement(Node* node);
    265   Reduction ReduceStoreTypedElement(Node* node);
    266   Reduction ReduceEffectPhi(Node* node);
    267   Reduction ReduceStart(Node* node);
    268   Reduction ReduceOtherNode(Node* node);
    269 
    270   Reduction UpdateState(Node* node, AbstractState const* state);
    271 
    272   AbstractState const* ComputeLoopState(Node* node,
    273                                         AbstractState const* state) const;
    274 
    275   static int FieldIndexOf(int offset);
    276   static int FieldIndexOf(FieldAccess const& access);
    277 
    278   CommonOperatorBuilder* common() const;
    279   AbstractState const* empty_state() const { return &empty_state_; }
    280   Factory* factory() const;
    281   Graph* graph() const;
    282   JSGraph* jsgraph() const { return jsgraph_; }
    283   Zone* zone() const { return node_states_.zone(); }
    284 
    285   AbstractState const empty_state_;
    286   AbstractStateForEffectNodes node_states_;
    287   JSGraph* const jsgraph_;
    288 
    289   DISALLOW_COPY_AND_ASSIGN(LoadElimination);
    290 };
    291 
    292 }  // namespace compiler
    293 }  // namespace internal
    294 }  // namespace v8
    295 
    296 #endif  // V8_COMPILER_LOAD_ELIMINATION_H_
    297