| 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_
 | 
| 
 |