Index: runtime/vm/flow_graph_builder.h |
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..df32ae7bfe32ba3281a451798b463ca89324274a |
--- /dev/null |
+++ b/runtime/vm/flow_graph_builder.h |
@@ -0,0 +1,222 @@ |
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+#ifndef VM_FLOW_GRAPH_BUILDER_H_ |
+#define VM_FLOW_GRAPH_BUILDER_H_ |
+ |
+#include "vm/allocation.h" |
+#include "vm/ast.h" |
+#include "vm/growable_array.h" |
+#include "vm/intermediate_language.h" |
+ |
+namespace dart { |
+ |
+class Instruction; |
+class ParsedFunction; |
+ |
+// Build a flow graph from a parsed function's AST. |
+class FlowGraphBuilder: public ValueObject { |
+ public: |
+ explicit FlowGraphBuilder(const ParsedFunction& parsed_function) |
+ : parsed_function_(parsed_function), |
+ bailout_reason_(NULL), |
+ postorder_() { } |
+ |
+ void BuildGraph(); |
+ |
+ const ParsedFunction& parsed_function() const { return parsed_function_; } |
+ |
+ bool HasBailedOut() const { return bailout_reason_ != NULL; } |
+ void Bailout(const char* reason) { |
+ // Cannot give a NULL reason because we use it to detect bailout. |
+ ASSERT(!HasBailedOut() && (reason != NULL)); |
+ bailout_reason_ = reason; |
+ } |
+ void TraceBailout() const; |
+ void PrintGraph() const; |
+ |
+ private: |
+ const ParsedFunction& parsed_function_; |
+ const char* bailout_reason_; |
+ GrowableArray<Instruction*> postorder_; |
+}; |
+ |
+ |
+#define DEFINE_VISIT(type, name) virtual void Visit##type(type* node); |
+ |
+class TestGraphVisitor; |
+ |
+// Translate an AstNode to a control-flow graph fragment for its effects |
+// (e.g., a statement or an expression in an effect context). Implements a |
+// function from an AstNode and next temporary index to a graph fragment |
+// with a single entry and at most one exit. The fragment is represented by |
+// an (entry, exit) pair of Instruction pointers: |
+// |
+// - (NULL, NULL): an empty and open graph fragment |
+// - (i0, NULL): a closed graph fragment which has only non-local exits |
+// - (i0, i1): an open graph fragment |
+class EffectGraphVisitor : public AstNodeVisitor { |
+ public: |
+ EffectGraphVisitor(FlowGraphBuilder* owner, intptr_t temp_index) |
+ : owner_(owner), |
+ temp_index_(temp_index), |
+ entry_(NULL), |
+ exit_(NULL) { } |
+ |
+ NODE_LIST(DEFINE_VISIT) |
+ |
+ FlowGraphBuilder* owner() const { return owner_; } |
+ intptr_t temp_index() const { return temp_index_; } |
+ Instruction* entry() const { return entry_; } |
+ Instruction* exit() const { return exit_; } |
+ |
+ bool is_empty() const { return entry_ == NULL; } |
+ bool is_open() const { return is_empty() || exit_ != NULL; } |
+ |
+ void Bailout(const char* reason); |
+ |
+ // Append a graph fragment to this graph. Assumes this graph is open. |
+ void Append(const EffectGraphVisitor& other_fragment); |
+ // Append a single instruction. Assumes this graph is open. |
+ void AddInstruction(Instruction* instruction); |
+ |
+ // Append a 'diamond' branch and join to this graph, depending on which |
+ // parts are reachable. Assumes this graph is open. |
+ void Join(const TestGraphVisitor& test_fragment, |
+ const EffectGraphVisitor& true_fragment, |
+ const EffectGraphVisitor& false_fragment); |
+ |
+ // Append a 'while loop' test and back edge to this graph, depending on |
+ // which parts are reachable. Afterward, the graph exit is the false |
+ // successor of the loop condition. |
+ void TieLoop(const TestGraphVisitor& test_fragment, |
+ const EffectGraphVisitor& body_fragment); |
+ |
+ protected: |
+ // Implement the core part of the translation of expression node types. |
+ AssertAssignableComp* TranslateAssignable(const AssignableNode& node); |
+ InstanceCallComp* TranslateBinaryOp(const BinaryOpNode& node); |
+ InstanceCallComp* TranslateComparison(const ComparisonNode& node); |
+ StoreLocalComp* TranslateStoreLocal(const StoreLocalNode& node); |
+ StaticCallComp* TranslateStaticCall(const StaticCallNode& node); |
+ |
+ void CloseFragment() { exit_ = NULL; } |
+ intptr_t AllocateTempIndex() { return temp_index_++; } |
+ |
+ private: |
+ // Helper to append a Do instruction to the graph. |
+ void DoComputation(Computation* computation) { |
+ AddInstruction(new DoInstr(computation)); |
+ } |
+ |
+ // Shared global state. |
+ FlowGraphBuilder* owner_; |
+ |
+ // Input parameters. |
+ intptr_t temp_index_; |
+ |
+ // Output parameters. |
+ Instruction* entry_; |
+ Instruction* exit_; |
+}; |
+ |
+ |
+// Translate an AstNode to a control-flow graph fragment for both its effects |
+// and value (e.g., for an expression in a value context). Implements a |
+// function from an AstNode and next temporary index to a graph fragment (as |
+// in the EffectGraphVisitor), a next temporary index, and an intermediate |
+// language Value. |
+class ValueGraphVisitor : public EffectGraphVisitor { |
+ public: |
+ ValueGraphVisitor(FlowGraphBuilder* owner, intptr_t temp_index) |
+ : EffectGraphVisitor(owner, temp_index), value_(NULL) { } |
+ |
+ NODE_LIST(DEFINE_VISIT) |
+ |
+ Value* value() const { return value_; } |
+ |
+ private: |
+ // Helper to set the output state to return a Value. |
+ void ReturnValue(Value* value) { value_ = value; } |
+ |
+ // Helper to append a Bind instruction to the graph and return its |
+ // temporary value (i.e., set the output parameters). |
+ void ReturnValueOf(Computation* computation) { |
+ AddInstruction(new BindInstr(temp_index(), computation)); |
+ value_ = new TempValue(AllocateTempIndex()); |
+ } |
+ |
+ // Output parameters. |
+ Value* value_; |
+}; |
+ |
+ |
+// Translate an AstNode to a control-flow graph fragment for both its |
+// effects and true/false control flow (e.g., for an expression in a test |
+// context). The resulting graph is always closed (even if it is empty) |
+// Successor control flow is explicitly set by a pair of pointers to |
+// TargetEntryInstr*. |
+// |
+// To distinguish between the graphs with only nonlocal exits and graphs |
+// with both true and false exits, there are a pair of TargetEntryInstr**: |
+// |
+// - Both NULL: only non-local exits, truly closed |
+// - Neither NULL: true and false successors at the given addresses |
+// |
+// We expect that AstNode in test contexts either have only nonlocal exits |
+// or else control flow has both true and false successors. |
+class TestGraphVisitor : public EffectGraphVisitor { |
+ public: |
+ TestGraphVisitor(FlowGraphBuilder* owner, intptr_t temp_index) |
+ : EffectGraphVisitor(owner, temp_index), |
+ true_successor_address_(NULL), |
+ false_successor_address_(NULL) { |
+ } |
+ |
+ NODE_LIST(DEFINE_VISIT) |
+ |
+ bool can_be_true() const { |
+ // Either both successors are set or neither is set. |
+ ASSERT((true_successor_address_ == NULL) == |
+ (false_successor_address_ == NULL)); |
+ return true_successor_address_ != NULL; |
+ } |
+ bool can_be_false() const { |
+ // Either both successors are set or neither is set. |
+ ASSERT((true_successor_address_ == NULL) == |
+ (false_successor_address_ == NULL)); |
+ return false_successor_address_ != NULL; |
+ } |
+ |
+ TargetEntryInstr** true_successor_address() const { |
+ ASSERT(can_be_true()); |
+ return true_successor_address_; |
+ } |
+ TargetEntryInstr** false_successor_address() const { |
+ ASSERT(can_be_false()); |
+ return false_successor_address_; |
+ } |
+ |
+ private: |
+ // Construct and concatenate a Branch instruction to this graph fragment. |
+ // Closes the fragment and sets the output parameters. |
+ void BranchOnValue(Value* value); |
+ |
+ // Helper to bind a computation and branch on its value. |
+ void BranchOnValueOf(Computation* computation) { |
+ AddInstruction(new BindInstr(temp_index(), computation)); |
+ BranchOnValue(new TempValue(temp_index())); |
+ } |
+ |
+ // Output parameters. |
+ TargetEntryInstr** true_successor_address_; |
+ TargetEntryInstr** false_successor_address_; |
+}; |
+ |
+#undef DEFINE_VISIT |
+ |
+ |
+} // namespace dart |
+ |
+#endif // VM_FLOW_GRAPH_BUILDER_H_ |