Home | History | Annotate | Download | only in src
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_DATAFLOW_H_
     29 #define V8_DATAFLOW_H_
     30 
     31 #include "v8.h"
     32 
     33 #include "ast.h"
     34 #include "compiler.h"
     35 #include "zone-inl.h"
     36 
     37 namespace v8 {
     38 namespace internal {
     39 
     40 // Forward declarations.
     41 class Node;
     42 
     43 class BitVector: public ZoneObject {
     44  public:
     45   // Iterator for the elements of this BitVector.
     46   class Iterator BASE_EMBEDDED {
     47    public:
     48     explicit Iterator(BitVector* target)
     49         : target_(target),
     50           current_index_(0),
     51           current_value_(target->data_[0]),
     52           current_(-1) {
     53       ASSERT(target->data_length_ > 0);
     54       Advance();
     55     }
     56     ~Iterator() { }
     57 
     58     bool Done() const { return current_index_ >= target_->data_length_; }
     59     void Advance();
     60 
     61     int Current() const {
     62       ASSERT(!Done());
     63       return current_;
     64     }
     65 
     66    private:
     67     uint32_t SkipZeroBytes(uint32_t val) {
     68       while ((val & 0xFF) == 0) {
     69         val >>= 8;
     70         current_ += 8;
     71       }
     72       return val;
     73     }
     74     uint32_t SkipZeroBits(uint32_t val) {
     75       while ((val & 0x1) == 0) {
     76         val >>= 1;
     77         current_++;
     78       }
     79       return val;
     80     }
     81 
     82     BitVector* target_;
     83     int current_index_;
     84     uint32_t current_value_;
     85     int current_;
     86 
     87     friend class BitVector;
     88   };
     89 
     90   explicit BitVector(int length)
     91       : length_(length),
     92         data_length_(SizeFor(length)),
     93         data_(ZONE->NewArray<uint32_t>(data_length_)) {
     94     ASSERT(length > 0);
     95     Clear();
     96   }
     97 
     98   BitVector(const BitVector& other)
     99       : length_(other.length()),
    100         data_length_(SizeFor(length_)),
    101         data_(ZONE->NewArray<uint32_t>(data_length_)) {
    102     CopyFrom(other);
    103   }
    104 
    105   static int SizeFor(int length) {
    106     return 1 + ((length - 1) / 32);
    107   }
    108 
    109   BitVector& operator=(const BitVector& rhs) {
    110     if (this != &rhs) CopyFrom(rhs);
    111     return *this;
    112   }
    113 
    114   void CopyFrom(const BitVector& other) {
    115     ASSERT(other.length() <= length());
    116     for (int i = 0; i < other.data_length_; i++) {
    117       data_[i] = other.data_[i];
    118     }
    119     for (int i = other.data_length_; i < data_length_; i++) {
    120       data_[i] = 0;
    121     }
    122   }
    123 
    124   bool Contains(int i) const {
    125     ASSERT(i >= 0 && i < length());
    126     uint32_t block = data_[i / 32];
    127     return (block & (1U << (i % 32))) != 0;
    128   }
    129 
    130   void Add(int i) {
    131     ASSERT(i >= 0 && i < length());
    132     data_[i / 32] |= (1U << (i % 32));
    133   }
    134 
    135   void Remove(int i) {
    136     ASSERT(i >= 0 && i < length());
    137     data_[i / 32] &= ~(1U << (i % 32));
    138   }
    139 
    140   void Union(const BitVector& other) {
    141     ASSERT(other.length() == length());
    142     for (int i = 0; i < data_length_; i++) {
    143       data_[i] |= other.data_[i];
    144     }
    145   }
    146 
    147   bool UnionIsChanged(const BitVector& other) {
    148     ASSERT(other.length() == length());
    149     bool changed = false;
    150     for (int i = 0; i < data_length_; i++) {
    151       uint32_t old_data = data_[i];
    152       data_[i] |= other.data_[i];
    153       if (data_[i] != old_data) changed = true;
    154     }
    155     return changed;
    156   }
    157 
    158   void Intersect(const BitVector& other) {
    159     ASSERT(other.length() == length());
    160     for (int i = 0; i < data_length_; i++) {
    161       data_[i] &= other.data_[i];
    162     }
    163   }
    164 
    165   void Subtract(const BitVector& other) {
    166     ASSERT(other.length() == length());
    167     for (int i = 0; i < data_length_; i++) {
    168       data_[i] &= ~other.data_[i];
    169     }
    170   }
    171 
    172   void Clear() {
    173     for (int i = 0; i < data_length_; i++) {
    174       data_[i] = 0;
    175     }
    176   }
    177 
    178   bool IsEmpty() const {
    179     for (int i = 0; i < data_length_; i++) {
    180       if (data_[i] != 0) return false;
    181     }
    182     return true;
    183   }
    184 
    185   bool Equals(const BitVector& other) {
    186     for (int i = 0; i < data_length_; i++) {
    187       if (data_[i] != other.data_[i]) return false;
    188     }
    189     return true;
    190   }
    191 
    192   int length() const { return length_; }
    193 
    194 #ifdef DEBUG
    195   void Print();
    196 #endif
    197 
    198  private:
    199   int length_;
    200   int data_length_;
    201   uint32_t* data_;
    202 };
    203 
    204 
    205 // An implementation of a sparse set whose elements are drawn from integers
    206 // in the range [0..universe_size[.  It supports constant-time Contains,
    207 // destructive Add, and destructuve Remove operations and linear-time (in
    208 // the number of elements) destructive Union.
    209 class SparseSet: public ZoneObject {
    210  public:
    211   // Iterator for sparse set elements.  Elements should not be added or
    212   // removed during iteration.
    213   class Iterator BASE_EMBEDDED {
    214    public:
    215     explicit Iterator(SparseSet* target) : target_(target), current_(0) {
    216       ASSERT(++target->iterator_count_ > 0);
    217     }
    218     ~Iterator() {
    219       ASSERT(target_->iterator_count_-- > 0);
    220     }
    221     bool Done() const { return current_ >= target_->dense_.length(); }
    222     void Advance() {
    223       ASSERT(!Done());
    224       ++current_;
    225     }
    226     int Current() {
    227       ASSERT(!Done());
    228       return target_->dense_[current_];
    229     }
    230 
    231    private:
    232     SparseSet* target_;
    233     int current_;
    234 
    235     friend class SparseSet;
    236   };
    237 
    238   explicit SparseSet(int universe_size)
    239       : dense_(4),
    240         sparse_(ZONE->NewArray<int>(universe_size)) {
    241 #ifdef DEBUG
    242     size_ = universe_size;
    243     iterator_count_ = 0;
    244 #endif
    245   }
    246 
    247   bool Contains(int n) const {
    248     ASSERT(0 <= n && n < size_);
    249     int dense_index = sparse_[n];
    250     return (0 <= dense_index) &&
    251         (dense_index < dense_.length()) &&
    252         (dense_[dense_index] == n);
    253   }
    254 
    255   void Add(int n) {
    256     ASSERT(0 <= n && n < size_);
    257     ASSERT(iterator_count_ == 0);
    258     if (!Contains(n)) {
    259       sparse_[n] = dense_.length();
    260       dense_.Add(n);
    261     }
    262   }
    263 
    264   void Remove(int n) {
    265     ASSERT(0 <= n && n < size_);
    266     ASSERT(iterator_count_ == 0);
    267     if (Contains(n)) {
    268       int dense_index = sparse_[n];
    269       int last = dense_.RemoveLast();
    270       if (dense_index < dense_.length()) {
    271         dense_[dense_index] = last;
    272         sparse_[last] = dense_index;
    273       }
    274     }
    275   }
    276 
    277   void Union(const SparseSet& other) {
    278     for (int i = 0; i < other.dense_.length(); ++i) {
    279       Add(other.dense_[i]);
    280     }
    281   }
    282 
    283  private:
    284   // The set is implemented as a pair of a growable dense list and an
    285   // uninitialized sparse array.
    286   ZoneList<int> dense_;
    287   int* sparse_;
    288 #ifdef DEBUG
    289   int size_;
    290   int iterator_count_;
    291 #endif
    292 };
    293 
    294 
    295 // Simple fixed-capacity list-based worklist (managed as a queue) of
    296 // pointers to T.
    297 template<typename T>
    298 class WorkList BASE_EMBEDDED {
    299  public:
    300   // The worklist cannot grow bigger than size.  We keep one item empty to
    301   // distinguish between empty and full.
    302   explicit WorkList(int size)
    303       : capacity_(size + 1), head_(0), tail_(0), queue_(capacity_) {
    304     for (int i = 0; i < capacity_; i++) queue_.Add(NULL);
    305   }
    306 
    307   bool is_empty() { return head_ == tail_; }
    308 
    309   bool is_full() {
    310     // The worklist is full if head is at 0 and tail is at capacity - 1:
    311     //   head == 0 && tail == capacity-1 ==> tail - head == capacity - 1
    312     // or if tail is immediately to the left of head:
    313     //   tail+1 == head  ==> tail - head == -1
    314     int diff = tail_ - head_;
    315     return (diff == -1 || diff == capacity_ - 1);
    316   }
    317 
    318   void Insert(T* item) {
    319     ASSERT(!is_full());
    320     queue_[tail_++] = item;
    321     if (tail_ == capacity_) tail_ = 0;
    322   }
    323 
    324   T* Remove() {
    325     ASSERT(!is_empty());
    326     T* item = queue_[head_++];
    327     if (head_ == capacity_) head_ = 0;
    328     return item;
    329   }
    330 
    331  private:
    332   int capacity_;  // Including one empty slot.
    333   int head_;      // Where the first item is.
    334   int tail_;      // Where the next inserted item will go.
    335   List<T*> queue_;
    336 };
    337 
    338 
    339 // Computes the set of assigned variables and annotates variables proxies
    340 // that are trivial sub-expressions and for-loops where the loop variable
    341 // is guaranteed to be a smi.
    342 class AssignedVariablesAnalyzer : public AstVisitor {
    343  public:
    344   static bool Analyze(CompilationInfo* info);
    345 
    346  private:
    347   AssignedVariablesAnalyzer(CompilationInfo* info, int bits);
    348   bool Analyze();
    349 
    350   Variable* FindSmiLoopVariable(ForStatement* stmt);
    351 
    352   int BitIndex(Variable* var);
    353 
    354   void RecordAssignedVar(Variable* var);
    355 
    356   void MarkIfTrivial(Expression* expr);
    357 
    358   // Visits an expression saving the accumulator before, clearing
    359   // it before visting and restoring it after visiting.
    360   void ProcessExpression(Expression* expr);
    361 
    362   // AST node visit functions.
    363 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
    364   AST_NODE_LIST(DECLARE_VISIT)
    365 #undef DECLARE_VISIT
    366 
    367   CompilationInfo* info_;
    368 
    369   // Accumulator for assigned variables set.
    370   BitVector av_;
    371 
    372   DISALLOW_COPY_AND_ASSIGN(AssignedVariablesAnalyzer);
    373 };
    374 
    375 
    376 } }  // namespace v8::internal
    377 
    378 
    379 #endif  // V8_DATAFLOW_H_
    380