OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #ifndef VM_FLOW_GRAPH_BUILDER_H_ |
| 6 #define VM_FLOW_GRAPH_BUILDER_H_ |
| 7 |
| 8 #include "vm/allocation.h" |
| 9 #include "vm/ast.h" |
| 10 #include "vm/growable_array.h" |
| 11 #include "vm/intermediate_language.h" |
| 12 |
| 13 namespace dart { |
| 14 |
| 15 class Instruction; |
| 16 class ParsedFunction; |
| 17 |
| 18 // Build a flow graph from a parsed function's AST. |
| 19 class FlowGraphBuilder: public ValueObject { |
| 20 public: |
| 21 explicit FlowGraphBuilder(const ParsedFunction& parsed_function) |
| 22 : parsed_function_(parsed_function), |
| 23 bailout_reason_(NULL), |
| 24 postorder_() { } |
| 25 |
| 26 void BuildGraph(); |
| 27 |
| 28 const ParsedFunction& parsed_function() const { return parsed_function_; } |
| 29 |
| 30 bool HasBailedOut() const { return bailout_reason_ != NULL; } |
| 31 void Bailout(const char* reason) { |
| 32 // Cannot give a NULL reason because we use it to detect bailout. |
| 33 ASSERT(!HasBailedOut() && (reason != NULL)); |
| 34 bailout_reason_ = reason; |
| 35 } |
| 36 void TraceBailout() const; |
| 37 void PrintGraph() const; |
| 38 |
| 39 private: |
| 40 const ParsedFunction& parsed_function_; |
| 41 const char* bailout_reason_; |
| 42 GrowableArray<Instruction*> postorder_; |
| 43 }; |
| 44 |
| 45 |
| 46 #define DEFINE_VISIT(type, name) virtual void Visit##type(type* node); |
| 47 |
| 48 class TestGraphVisitor; |
| 49 |
| 50 // Translate an AstNode to a control-flow graph fragment for its effects |
| 51 // (e.g., a statement or an expression in an effect context). Implements a |
| 52 // function from an AstNode and next temporary index to a graph fragment |
| 53 // with a single entry and at most one exit. The fragment is represented by |
| 54 // an (entry, exit) pair of Instruction pointers: |
| 55 // |
| 56 // - (NULL, NULL): an empty and open graph fragment |
| 57 // - (i0, NULL): a closed graph fragment which has only non-local exits |
| 58 // - (i0, i1): an open graph fragment |
| 59 class EffectGraphVisitor : public AstNodeVisitor { |
| 60 public: |
| 61 EffectGraphVisitor(FlowGraphBuilder* owner, intptr_t temp_index) |
| 62 : owner_(owner), |
| 63 temp_index_(temp_index), |
| 64 entry_(NULL), |
| 65 exit_(NULL) { } |
| 66 |
| 67 NODE_LIST(DEFINE_VISIT) |
| 68 |
| 69 FlowGraphBuilder* owner() const { return owner_; } |
| 70 intptr_t temp_index() const { return temp_index_; } |
| 71 Instruction* entry() const { return entry_; } |
| 72 Instruction* exit() const { return exit_; } |
| 73 |
| 74 bool is_empty() const { return entry_ == NULL; } |
| 75 bool is_open() const { return is_empty() || exit_ != NULL; } |
| 76 |
| 77 void Bailout(const char* reason); |
| 78 |
| 79 // Append a graph fragment to this graph. Assumes this graph is open. |
| 80 void Append(const EffectGraphVisitor& other_fragment); |
| 81 // Append a single instruction. Assumes this graph is open. |
| 82 void AddInstruction(Instruction* instruction); |
| 83 |
| 84 // Append a 'diamond' branch and join to this graph, depending on which |
| 85 // parts are reachable. Assumes this graph is open. |
| 86 void Join(const TestGraphVisitor& test_fragment, |
| 87 const EffectGraphVisitor& true_fragment, |
| 88 const EffectGraphVisitor& false_fragment); |
| 89 |
| 90 // Append a 'while loop' test and back edge to this graph, depending on |
| 91 // which parts are reachable. Afterward, the graph exit is the false |
| 92 // successor of the loop condition. |
| 93 void TieLoop(const TestGraphVisitor& test_fragment, |
| 94 const EffectGraphVisitor& body_fragment); |
| 95 |
| 96 protected: |
| 97 // Implement the core part of the translation of expression node types. |
| 98 AssertAssignableComp* TranslateAssignable(const AssignableNode& node); |
| 99 InstanceCallComp* TranslateBinaryOp(const BinaryOpNode& node); |
| 100 InstanceCallComp* TranslateComparison(const ComparisonNode& node); |
| 101 StoreLocalComp* TranslateStoreLocal(const StoreLocalNode& node); |
| 102 StaticCallComp* TranslateStaticCall(const StaticCallNode& node); |
| 103 |
| 104 void CloseFragment() { exit_ = NULL; } |
| 105 intptr_t AllocateTempIndex() { return temp_index_++; } |
| 106 |
| 107 private: |
| 108 // Helper to append a Do instruction to the graph. |
| 109 void DoComputation(Computation* computation) { |
| 110 AddInstruction(new DoInstr(computation)); |
| 111 } |
| 112 |
| 113 // Shared global state. |
| 114 FlowGraphBuilder* owner_; |
| 115 |
| 116 // Input parameters. |
| 117 intptr_t temp_index_; |
| 118 |
| 119 // Output parameters. |
| 120 Instruction* entry_; |
| 121 Instruction* exit_; |
| 122 }; |
| 123 |
| 124 |
| 125 // Translate an AstNode to a control-flow graph fragment for both its effects |
| 126 // and value (e.g., for an expression in a value context). Implements a |
| 127 // function from an AstNode and next temporary index to a graph fragment (as |
| 128 // in the EffectGraphVisitor), a next temporary index, and an intermediate |
| 129 // language Value. |
| 130 class ValueGraphVisitor : public EffectGraphVisitor { |
| 131 public: |
| 132 ValueGraphVisitor(FlowGraphBuilder* owner, intptr_t temp_index) |
| 133 : EffectGraphVisitor(owner, temp_index), value_(NULL) { } |
| 134 |
| 135 NODE_LIST(DEFINE_VISIT) |
| 136 |
| 137 Value* value() const { return value_; } |
| 138 |
| 139 private: |
| 140 // Helper to set the output state to return a Value. |
| 141 void ReturnValue(Value* value) { value_ = value; } |
| 142 |
| 143 // Helper to append a Bind instruction to the graph and return its |
| 144 // temporary value (i.e., set the output parameters). |
| 145 void ReturnValueOf(Computation* computation) { |
| 146 AddInstruction(new BindInstr(temp_index(), computation)); |
| 147 value_ = new TempValue(AllocateTempIndex()); |
| 148 } |
| 149 |
| 150 // Output parameters. |
| 151 Value* value_; |
| 152 }; |
| 153 |
| 154 |
| 155 // Translate an AstNode to a control-flow graph fragment for both its |
| 156 // effects and true/false control flow (e.g., for an expression in a test |
| 157 // context). The resulting graph is always closed (even if it is empty) |
| 158 // Successor control flow is explicitly set by a pair of pointers to |
| 159 // TargetEntryInstr*. |
| 160 // |
| 161 // To distinguish between the graphs with only nonlocal exits and graphs |
| 162 // with both true and false exits, there are a pair of TargetEntryInstr**: |
| 163 // |
| 164 // - Both NULL: only non-local exits, truly closed |
| 165 // - Neither NULL: true and false successors at the given addresses |
| 166 // |
| 167 // We expect that AstNode in test contexts either have only nonlocal exits |
| 168 // or else control flow has both true and false successors. |
| 169 class TestGraphVisitor : public EffectGraphVisitor { |
| 170 public: |
| 171 TestGraphVisitor(FlowGraphBuilder* owner, intptr_t temp_index) |
| 172 : EffectGraphVisitor(owner, temp_index), |
| 173 true_successor_address_(NULL), |
| 174 false_successor_address_(NULL) { |
| 175 } |
| 176 |
| 177 NODE_LIST(DEFINE_VISIT) |
| 178 |
| 179 bool can_be_true() const { |
| 180 // Either both successors are set or neither is set. |
| 181 ASSERT((true_successor_address_ == NULL) == |
| 182 (false_successor_address_ == NULL)); |
| 183 return true_successor_address_ != NULL; |
| 184 } |
| 185 bool can_be_false() const { |
| 186 // Either both successors are set or neither is set. |
| 187 ASSERT((true_successor_address_ == NULL) == |
| 188 (false_successor_address_ == NULL)); |
| 189 return false_successor_address_ != NULL; |
| 190 } |
| 191 |
| 192 TargetEntryInstr** true_successor_address() const { |
| 193 ASSERT(can_be_true()); |
| 194 return true_successor_address_; |
| 195 } |
| 196 TargetEntryInstr** false_successor_address() const { |
| 197 ASSERT(can_be_false()); |
| 198 return false_successor_address_; |
| 199 } |
| 200 |
| 201 private: |
| 202 // Construct and concatenate a Branch instruction to this graph fragment. |
| 203 // Closes the fragment and sets the output parameters. |
| 204 void BranchOnValue(Value* value); |
| 205 |
| 206 // Helper to bind a computation and branch on its value. |
| 207 void BranchOnValueOf(Computation* computation) { |
| 208 AddInstruction(new BindInstr(temp_index(), computation)); |
| 209 BranchOnValue(new TempValue(temp_index())); |
| 210 } |
| 211 |
| 212 // Output parameters. |
| 213 TargetEntryInstr** true_successor_address_; |
| 214 TargetEntryInstr** false_successor_address_; |
| 215 }; |
| 216 |
| 217 #undef DEFINE_VISIT |
| 218 |
| 219 |
| 220 } // namespace dart |
| 221 |
| 222 #endif // VM_FLOW_GRAPH_BUILDER_H_ |
OLD | NEW |