blob: 79d760f5a4267433f41c7847482ac9e3acefcdf7 [file] [log] [blame]
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001// 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
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000031#include "v8.h"
32
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000033#include "ast.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "compiler.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000035#include "zone-inl.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000036
37namespace v8 {
38namespace internal {
39
ager@chromium.orgb26c50a2010-03-26 09:27:16 +000040// Forward declarations.
41class Node;
42
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000043class BitVector: public ZoneObject {
44 public:
kasperl@chromium.orga5551262010-12-07 12:49:48 +000045 // 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() { }
ricow@chromium.org65fae842010-08-25 15:26:24 +000057
kasperl@chromium.orga5551262010-12-07 12:49:48 +000058 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();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000096 }
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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000105 static int SizeFor(int length) {
106 return 1 + ((length - 1) / 32);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000107 }
108
109 BitVector& operator=(const BitVector& rhs) {
110 if (this != &rhs) CopyFrom(rhs);
111 return *this;
112 }
113
114 void CopyFrom(const BitVector& other) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000115 ASSERT(other.length() <= length());
116 for (int i = 0; i < other.data_length_; i++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000117 data_[i] = other.data_[i];
118 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000119 for (int i = other.data_length_; i < data_length_; i++) {
120 data_[i] = 0;
121 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000122 }
123
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000124 bool Contains(int i) const {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000125 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000147 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
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000158 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
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000165 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
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000172 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
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000185 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
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000192 int length() const { return length_; }
193
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000194#ifdef DEBUG
195 void Print();
196#endif
197
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000198 private:
199 int length_;
200 int data_length_;
201 uint32_t* data_;
202};
203
204
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000205// 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
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000295// Simple fixed-capacity list-based worklist (managed as a queue) of
296// pointers to T.
297template<typename T>
298class WorkList BASE_EMBEDDED {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000299 public:
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000300 // 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 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000306
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000307 bool is_empty() { return head_ == tail_; }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000308
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000309 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 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000317
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000318 void Insert(T* item) {
319 ASSERT(!is_full());
320 queue_[tail_++] = item;
321 if (tail_ == capacity_) tail_ = 0;
322 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000323
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000324 T* Remove() {
325 ASSERT(!is_empty());
326 T* item = queue_[head_++];
327 if (head_ == capacity_) head_ = 0;
328 return item;
329 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000330
331 private:
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000332 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
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000339// 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:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000344 static bool Analyze(CompilationInfo* info);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000345
346 private:
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000347 AssignedVariablesAnalyzer(CompilationInfo* info, int bits);
348 bool Analyze();
349
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000350 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
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000367 CompilationInfo* info_;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000368
369 // Accumulator for assigned variables set.
370 BitVector av_;
371
372 DISALLOW_COPY_AND_ASSIGN(AssignedVariablesAnalyzer);
373};
374
375
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000376} } // namespace v8::internal
377
ager@chromium.org5c838252010-02-19 08:53:10 +0000378
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000379#endif // V8_DATAFLOW_H_