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
37namespace v8 {
38namespace internal {
39
40// Forward declarations.
41class Node;
42
43class 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.
209class 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.
297template<typename T>
298class 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.
342class 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