Index: src/hydrogen-flow-engine.h |
diff --git a/src/hydrogen-flow-engine.h b/src/hydrogen-flow-engine.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8b836d2340fe2ca7790274cd19cfa82ad549bc62 |
--- /dev/null |
+++ b/src/hydrogen-flow-engine.h |
@@ -0,0 +1,235 @@ |
+// Copyright 2013 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_HYDROGEN_FLOW_ENGINE_H_ |
+#define V8_HYDROGEN_FLOW_ENGINE_H_ |
+ |
+#include "hydrogen.h" |
+#include "hydrogen-instructions.h" |
+#include "zone.h" |
+ |
+namespace v8 { |
+namespace internal { |
+ |
+// An example implementation of effects that doesn't collect anything. |
+class NoEffects : public ZoneObject { |
+ public: |
+ explicit NoEffects(Zone* zone) { } |
+ |
+ inline bool Disabled() { |
+ return true; // Nothing to do. |
+ } |
+ template <class State> |
+ inline void Apply(State* state) { |
+ // do nothing. |
+ } |
+ inline void Process(HInstruction* value, Zone* zone) { |
+ // do nothing. |
+ } |
+ inline void Union(NoEffects* other, Zone* zone) { |
+ // do nothing. |
+ } |
+}; |
+ |
+ |
+// An example implementation of state that doesn't track anything. |
+class NoState { |
+ public: |
+ inline NoState* Copy(HBasicBlock* succ, Zone* zone) { |
+ return this; |
+ } |
+ inline NoState* Process(HInstruction* value, Zone* zone) { |
+ return this; |
+ } |
+ inline NoState* Merge(HBasicBlock* succ, NoState* other, Zone* zone) { |
+ return this; |
+ } |
+}; |
+ |
+ |
+// This class implements an engine that can drive flow-sensitive analyses |
+// over a graph of basic blocks, either one block at a time (local analysis) |
+// or over the entire graph (global analysis). The flow engine is parameterized |
+// by the type of the state and the effects collected while walking over the |
+// graph. |
+// |
+// The "State" collects which facts are known while passing over instructions |
+// in control flow order, and the "Effects" collect summary information about |
+// which facts could be invalidated on other control flow paths. The effects |
+// are necessary to correctly handle loops in the control flow graph without |
+// doing a fixed-point iteration. Thus the flow engine is guaranteed to visit |
+// each block at most twice; once for state, and optionally once for effects. |
+// |
+// The flow engine requires the State and Effects classes to implement methods |
+// like the example NoState and NoEffects above. It's not necessary to provide |
+// an effects implementation for local analysis. |
+template <class State, class Effects> |
+class HFlowEngine { |
+ public: |
+ HFlowEngine(HGraph* graph, Zone* zone) |
+ : graph_(graph), |
+ zone_(zone), |
+#if DEBUG |
+ pred_counts_(graph->blocks()->length(), zone), |
+#endif |
+ block_states_(graph->blocks()->length(), zone), |
+ loop_effects_(graph->blocks()->length(), zone) { |
+ loop_effects_.AddBlock(NULL, graph_->blocks()->length(), zone); |
+ } |
+ |
+ // Local analysis. Iterates over the instructions in the given block. |
+ State* AnalyzeOneBlock(HBasicBlock* block, State* state) { |
+ // Go through all instructions of the current block, updating the state. |
+ for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
+ state = state->Process(it.Current(), zone_); |
+ } |
+ return StateAt(block); |
+ } |
+ |
+ // Global analysis. Iterates over all blocks that are dominated by the given |
+ // block, starting with the initial state. Computes effects for nested loops. |
+ void AnalyzeDominatedBlocks(HBasicBlock* root, State* initial) { |
+ InitializeStates(); |
+ SetStateAt(root, initial); |
+ |
+ // Iterate all dominated blocks starting from the given start block. |
+ for (int i = root->block_id(); i < graph_->blocks()->length(); i++) { |
+ HBasicBlock* block = graph_->blocks()->at(i); |
+ |
+ // Skip blocks not dominated by the root node. |
+ if (SkipNonDominatedBlock(root, block)) continue; |
+ State* state = StateAt(block); |
+ |
+ if (block->IsLoopHeader()) { |
+ // Apply loop effects before analyzing loop body. |
+ ComputeLoopEffects(block)->Apply(state); |
+ } else { |
+ // Must have visited all predecessors before this block. |
+ CheckPredecessorCount(block); |
+ } |
+ |
+ // Go through all instructions of the current block, updating the state. |
+ for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
+ state = state->Process(it.Current(), zone_); |
+ } |
+ |
+ // Propagate the block state forward to all successor blocks. |
+ for (int i = 0; i < block->end()->SuccessorCount(); i++) { |
+ HBasicBlock* succ = block->end()->SuccessorAt(i); |
+ IncrementPredecessorCount(succ); |
+ if (StateAt(succ) == NULL) { |
+ // This is the first state to reach the successor. |
+ SetStateAt(succ, state->Copy(succ, zone_)); |
+ } else { |
+ // Merge the current state with the state already at the successor. |
+ SetStateAt(succ, state->Merge(succ, StateAt(succ), zone_)); |
+ } |
+ } |
+ } |
+ } |
+ |
+ private: |
+ // Computes and caches the loop effects for the loop which has the given |
+ // block as its loop header. |
+ Effects* ComputeLoopEffects(HBasicBlock* block) { |
+ ASSERT(block->IsLoopHeader()); |
+ Effects* effects = loop_effects_[block->block_id()]; |
+ if (effects != NULL) return effects; // Already analyzed this loop. |
+ |
+ effects = new(zone_) Effects(zone_); |
+ loop_effects_[block->block_id()] = effects; |
+ if (effects->Disabled()) return effects; // No effects for this analysis. |
+ |
+ HLoopInformation* loop = block->loop_information(); |
+ int end = loop->GetLastBackEdge()->block_id(); |
+ // Process the blocks between the header and the end. |
+ for (int i = block->block_id(); i <= end; i++) { |
+ HBasicBlock* member = graph_->blocks()->at(i); |
+ if (i != block->block_id() && member->IsLoopHeader()) { |
+ // Recursively compute and cache the effects of the nested loop. |
+ ASSERT(member->loop_information()->parent_loop() == loop); |
+ Effects* nested = ComputeLoopEffects(member); |
+ effects->Union(nested, zone_); |
+ // Skip the nested loop's blocks. |
+ i = member->loop_information()->GetLastBackEdge()->block_id(); |
+ } else { |
+ // Process all the effects of the block. |
+ ASSERT(member->current_loop() == loop); |
+ for (HInstructionIterator it(member); !it.Done(); it.Advance()) { |
+ effects->Process(it.Current(), zone_); |
+ } |
+ } |
+ } |
+ return effects; |
+ } |
+ |
+ inline bool SkipNonDominatedBlock(HBasicBlock* root, HBasicBlock* other) { |
+ if (root->block_id() == 0) return false; // Visit the whole graph. |
+ if (root == other) return false; // Always visit the root. |
+ return !root->Dominates(other); // Only visit dominated blocks. |
+ } |
+ |
+ inline State* StateAt(HBasicBlock* block) { |
+ return block_states_.at(block->block_id()); |
+ } |
+ |
+ inline void SetStateAt(HBasicBlock* block, State* state) { |
+ block_states_.Set(block->block_id(), state); |
+ } |
+ |
+ inline void InitializeStates() { |
+#if DEBUG |
+ pred_counts_.Rewind(0); |
+ pred_counts_.AddBlock(0, graph_->blocks()->length(), zone_); |
+#endif |
+ block_states_.Rewind(0); |
+ block_states_.AddBlock(NULL, graph_->blocks()->length(), zone_); |
+ } |
+ |
+ inline void CheckPredecessorCount(HBasicBlock* block) { |
+ ASSERT(block->predecessors()->length() == pred_counts_[block->block_id()]); |
+ } |
+ |
+ inline void IncrementPredecessorCount(HBasicBlock* block) { |
+#if DEBUG |
+ pred_counts_[block->block_id()]++; |
+#endif |
+ } |
+ |
+ HGraph* graph_; // The hydrogen graph. |
+ Zone* zone_; // Temporary zone. |
+#if DEBUG |
+ ZoneList<int> pred_counts_; // Finished predecessors (by block id). |
+#endif |
+ ZoneList<State*> block_states_; // Block states (by block id). |
+ ZoneList<Effects*> loop_effects_; // Loop effects (by block id). |
+}; |
+ |
+ |
+} } // namespace v8::internal |
+ |
+#endif // V8_HYDROGEN_FLOW_ENGINE_H_ |