// Copyright 2010 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef V8_DATAFLOW_H_ #define V8_DATAFLOW_H_ #include "v8.h" #include "ast.h" #include "compiler.h" #include "zone-inl.h" namespace v8 { namespace internal { // Forward declarations. class Node; class BitVector: public ZoneObject { public: BitVector() : length_(0), data_length_(0), data_(NULL) { } explicit BitVector(int length) { ExpandTo(length); } BitVector(const BitVector& other) : length_(other.length()), data_length_(SizeFor(length_)), data_(Zone::NewArray(data_length_)) { CopyFrom(other); } void ExpandTo(int length) { ASSERT(length > 0); length_ = length; data_length_ = SizeFor(length); data_ = Zone::NewArray(data_length_); Clear(); } BitVector& operator=(const BitVector& rhs) { if (this != &rhs) CopyFrom(rhs); return *this; } void CopyFrom(const BitVector& other) { ASSERT(other.length() == length()); for (int i = 0; i < data_length_; i++) { data_[i] = other.data_[i]; } } bool Contains(int i) { ASSERT(i >= 0 && i < length()); uint32_t block = data_[i / 32]; return (block & (1U << (i % 32))) != 0; } void Add(int i) { ASSERT(i >= 0 && i < length()); data_[i / 32] |= (1U << (i % 32)); } void Remove(int i) { ASSERT(i >= 0 && i < length()); data_[i / 32] &= ~(1U << (i % 32)); } void Union(const BitVector& other) { ASSERT(other.length() == length()); for (int i = 0; i < data_length_; i++) { data_[i] |= other.data_[i]; } } void Intersect(const BitVector& other) { ASSERT(other.length() == length()); for (int i = 0; i < data_length_; i++) { data_[i] &= other.data_[i]; } } void Subtract(const BitVector& other) { ASSERT(other.length() == length()); for (int i = 0; i < data_length_; i++) { data_[i] &= ~other.data_[i]; } } void Clear() { for (int i = 0; i < data_length_; i++) { data_[i] = 0; } } bool IsEmpty() const { for (int i = 0; i < data_length_; i++) { if (data_[i] != 0) return false; } return true; } bool Equals(const BitVector& other) { for (int i = 0; i < data_length_; i++) { if (data_[i] != other.data_[i]) return false; } return true; } int length() const { return length_; } #ifdef DEBUG void Print(); #endif private: static int SizeFor(int length) { return 1 + ((length - 1) / 32); } int length_; int data_length_; uint32_t* data_; }; // Simple fixed-capacity list-based worklist (managed as a queue) of // pointers to T. template class WorkList BASE_EMBEDDED { public: // The worklist cannot grow bigger than size. We keep one item empty to // distinguish between empty and full. explicit WorkList(int size) : capacity_(size + 1), head_(0), tail_(0), queue_(capacity_) { for (int i = 0; i < capacity_; i++) queue_.Add(NULL); } bool is_empty() { return head_ == tail_; } bool is_full() { // The worklist is full if head is at 0 and tail is at capacity - 1: // head == 0 && tail == capacity-1 ==> tail - head == capacity - 1 // or if tail is immediately to the left of head: // tail+1 == head ==> tail - head == -1 int diff = tail_ - head_; return (diff == -1 || diff == capacity_ - 1); } void Insert(T* item) { ASSERT(!is_full()); queue_[tail_++] = item; if (tail_ == capacity_) tail_ = 0; } T* Remove() { ASSERT(!is_empty()); T* item = queue_[head_++]; if (head_ == capacity_) head_ = 0; return item; } private: int capacity_; // Including one empty slot. int head_; // Where the first item is. int tail_; // Where the next inserted item will go. List queue_; }; // Computes the set of assigned variables and annotates variables proxies // that are trivial sub-expressions and for-loops where the loop variable // is guaranteed to be a smi. class AssignedVariablesAnalyzer : public AstVisitor { public: explicit AssignedVariablesAnalyzer() : info_(NULL) { } bool Analyze(CompilationInfo* info); private: Variable* FindSmiLoopVariable(ForStatement* stmt); int BitIndex(Variable* var); void RecordAssignedVar(Variable* var); void MarkIfTrivial(Expression* expr); // Visits an expression saving the accumulator before, clearing // it before visting and restoring it after visiting. void ProcessExpression(Expression* expr); // AST node visit functions. #define DECLARE_VISIT(type) virtual void Visit##type(type* node); AST_NODE_LIST(DECLARE_VISIT) #undef DECLARE_VISIT CompilationInfo* info_; // Accumulator for assigned variables set. BitVector av_; DISALLOW_COPY_AND_ASSIGN(AssignedVariablesAnalyzer); }; } } // namespace v8::internal #endif // V8_DATAFLOW_H_