| // Copyright (c) 2016, 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. |
| |
| import '../elements/elements.dart'; |
| import '../types/types.dart'; |
| import 'nodes.dart'; |
| |
| /// Base class for objects that build up an SSA graph. |
| /// |
| /// This contains helpers for building the graph and tracking information about |
| /// the current state of the graph being built. |
| abstract class GraphBuilder { |
| /// Holds the resulting SSA graph. |
| final HGraph graph = new HGraph(); |
| |
| HBasicBlock _current; |
| |
| /// The current block to add instructions to. Might be null, if we are |
| /// visiting dead code, but see [isReachable]. |
| HBasicBlock get current => _current; |
| |
| void set current(c) { |
| isReachable = c != null; |
| _current = c; |
| } |
| |
| /// The most recently opened block. Has the same value as [current] while |
| /// the block is open, but unlike [current], it isn't cleared when the |
| /// current block is closed. |
| HBasicBlock lastOpenedBlock; |
| |
| /// Indicates whether the current block is dead (because it has a throw or a |
| /// return further up). If this is false, then [current] may be null. If the |
| /// block is dead then it may also be aborted, but for simplicity we only |
| /// abort on statement boundaries, not in the middle of expressions. See |
| /// [isAborted]. |
| bool isReachable = true; |
| |
| HParameterValue lastAddedParameter; |
| |
| Map<ParameterElement, HInstruction> parameters = |
| <ParameterElement, HInstruction>{}; |
| |
| HBasicBlock addNewBlock() { |
| HBasicBlock block = graph.addNewBlock(); |
| // If adding a new block during building of an expression, it is due to |
| // conditional expressions or short-circuit logical operators. |
| return block; |
| } |
| |
| void open(HBasicBlock block) { |
| block.open(); |
| current = block; |
| lastOpenedBlock = block; |
| } |
| |
| HBasicBlock close(HControlFlow end) { |
| HBasicBlock result = current; |
| current.close(end); |
| current = null; |
| return result; |
| } |
| |
| HBasicBlock closeAndGotoExit(HControlFlow end) { |
| HBasicBlock result = current; |
| current.close(end); |
| current = null; |
| result.addSuccessor(graph.exit); |
| return result; |
| } |
| |
| void goto(HBasicBlock from, HBasicBlock to) { |
| from.close(new HGoto()); |
| from.addSuccessor(to); |
| } |
| |
| bool isAborted() { |
| return current == null; |
| } |
| |
| /// Creates a new block, transitions to it from any current block, and |
| /// opens the new block. |
| HBasicBlock openNewBlock() { |
| HBasicBlock newBlock = addNewBlock(); |
| if (!isAborted()) goto(current, newBlock); |
| open(newBlock); |
| return newBlock; |
| } |
| |
| void add(HInstruction instruction) { |
| current.add(instruction); |
| } |
| |
| HParameterValue addParameter(Entity parameter, TypeMask type) { |
| HParameterValue result = new HParameterValue(parameter, type); |
| if (lastAddedParameter == null) { |
| graph.entry.addBefore(graph.entry.first, result); |
| } else { |
| graph.entry.addAfter(lastAddedParameter, result); |
| } |
| lastAddedParameter = result; |
| return result; |
| } |
| } |