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