summaryrefslogtreecommitdiff
path: root/SIP/compiler-phase-init/sip.xhtml
diff options
context:
space:
mode:
Diffstat (limited to 'SIP/compiler-phase-init/sip.xhtml')
-rw-r--r--SIP/compiler-phase-init/sip.xhtml1546
1 files changed, 1546 insertions, 0 deletions
diff --git a/SIP/compiler-phase-init/sip.xhtml b/SIP/compiler-phase-init/sip.xhtml
new file mode 100644
index 0000000000..10cb4c3189
--- /dev/null
+++ b/SIP/compiler-phase-init/sip.xhtml
@@ -0,0 +1,1546 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Scala Compiler Phase and Plug-In Initialization</title>
+ <meta name="sip" content="00002"/>
+ <meta name="author" content="Anders Bach Nielsen"/>
+ <meta name="version" content="0"/>
+ <meta name="type" content="standards"/>
+ <meta name="status" content="submission"/>
+ <meta name="created" content="2008-08-25"/>
+ <meta name="updated" content="2008-10-09"/>
+ <meta name="scala-version" content="2.8.0.final-"/>
+ <meta name="owner-contact" content="mailto:andersbach.nielsen@epfl.ch"/>
+ <meta name="discussion" content="http://www.nabble.com/SIP-00002%3A-Compiler-Phase-Initialization-and-Plugins-td19677473.html"/>
+ <!-- <link rel="auxiliary" href="[URI]" type="[mime type]"/> -->
+ <!-- <link rel="replaces" href="[URI]" type="application/xhtml+xml"/> -->
+ <!-- <link rel="depends-on" href="[URI]" type="application/xhtml+xml"/> -->
+ <!-- Stylesheet -->
+ <link rel="stylesheet" href="http://lampsvn.epfl.ch/svn-repos/scala/sip/trunk/sip.css" type="text/css"/>
+</head>
+<body>
+ <a name="top"></a>
+ <h1>Scala Compiler Phase and Plug-In Initialization</h1>
+
+ <h2>Abstract</h2>
+
+ <p>This document describes the design and implementation of a more
+ uniform way of handling internal compiler phases and external user
+ supplied phases via plug-ins in the Scala compiler.</p>
+
+ <h2>Contents</h2>
+
+ <ul>
+ <li><a href="#motivation">Motivation</a>
+ <ul>
+ <li><a href="#goalsandreq">Goals</a></li>
+ <li><a href="#usecases">Use Cases</a></li>
+ <li><a href="#detailedusecases">Detailed Use Cases</a>
+ <ul>
+ <li><a href="#usecase1">Assembling compiler internal phases for the JVM target ...</a></li>
+ <li><a href="#usecase2">Assembling compiler internal phases for the MSIL target ...</a></li>
+ <li><a href="#usecase3">Adding one plug-in supplied phase to the JVM target ...</a></li>
+ <li><a href="#usecase4">Adding two plug-in supplied phase to the JVM target ...</a></li>
+ <li><a href="#usecase5">Adding two plug-in supplied phases, where one has a ...</a></li>
+ <li><a href="#usecase6">Adding plug-in supplied phases with dependencies to ...</a></li>
+ <li><a href="#usecase7">Two separate phases that should be handled as a single ...</a></li>
+ <li><a href="#usecase8">A cyclic dependency among phases is a fatal error.</a></li>
+ <li><a href="#usecase9">Special handling of the <code>parser</code> and <code>terminal</code> phases.</a></li>
+ <li><a href="#usecase10">Larger compiler example with three plug-in supplied phases.</a></li>
+ </ul>
+ </li>
+ <li><a href="#futuregoals">Future Goals That Extend Beyond This Proposal</a></li>
+ </ul>
+ </li>
+ <li><a href="#description">Description</a>
+ <ul>
+ <li><a href="#presentdesign">The Present Design</a></li>
+ <li><a href="#proposeddesign">The Proposed Design</a>
+ <ul>
+ <li><a href="#propdesign1">Internal Phases</a></li>
+ <li><a href="#propdesign2">External Phases</a></li>
+ <li><a href="#propdesign3">Phases Set</a></li>
+ <li><a href="#propdesign4">Phase Assembly</a></li>
+ <li><a href="#propdesign5">Constraint System</a></li>
+ <li><a href="#constsolver">Constraint Solving Algorithm</a></li>
+ </ul>
+ </li>
+ <li><a href="#namingscheme">Naming Scheme for Internal and External Phases</a></li>
+ <li><a href="#implications">Implications of This Proposal</a></li>
+ </ul>
+ </li>
+ <li><a href="#implementation">Implementation</a></li>
+ </ul>
+
+
+ <a name="motivation"></a>
+ <h2>Motivation</h2>
+
+ <p>This section will cover the motivating goals of creating this
+ proposal and some use cases emphasizing these goals. There will also
+ be a section on goals that extend beyond this proposal and will
+ therefore not be covered by this proposal.</p>
+
+ <a name="goalsandreq"></a>
+ <h3>Goals</h3>
+
+ <ul>
+ <li>Handle inclusion and constraints for internal compiler phases
+ and external user supplied phases via plug-ins in a uniform
+ way.</li>
+
+ <li>Phase ordering is based on a simple, but sufficient powerful
+ and solvable constraint system.</li>
+
+ <li>Phase ordering of internal compiler phases and external user
+ supplied phases should retain as much compatibility with the
+ current scheme as possible.</li>
+
+ <li>Phase ordering is fully determined by the set of input phases.
+ It does not matter, for example, what order the compiler processes
+ the individual plug-ins that supply the external phases.</li>
+
+ <li>Ordering of the internal compiler phases should always succeed
+ in a valid compiler phase chain. Adding two plug-ins, which by
+ themselves give a valid compiler phase chain, should also give a
+ valid compiler phase chain.</li>
+
+ </ul>
+
+ <a name="usecases"></a> <h3>Use Cases</h3>
+
+ <ol>
+ <li><a href="#usecase1">Assembling compiler internal phases for
+ the JVM target and no plug-ins are loaded.</a></li>
+
+ <li><a href="#usecase2">Assembling compiler internal phases for
+ the MSIL target and no plug-ins are loaded.</a></li>
+
+ <li><a href="#usecase3">Adding one plug-in supplied phase to the
+ JVM target compiler after type checking.</a></li>
+
+ <li><a href="#usecase4">Adding two plug-in supplied phase to the
+ JVM target compiler after type checking.</a></li>
+
+ <li><a href="#usecase5">Adding two plug-in supplied phases, where
+ one has a dependency on the other, to the JVM target
+ compiler.</a></li>
+
+ <li><a href="#usecase6">Adding plug-in supplied phases with
+ dependencies to both plug-in supplied and internal phases to the
+ JVM target compiler.</a></li>
+
+ <li><a href="#usecase7">Two separate phases that should be handled
+ as a single phase.</a></li>
+
+ <li><a href="#usecase8">A cyclic dependency among phases is a
+ fatal error.</a></li>
+
+ <li><a href="#usecase9">Special handling of the
+ <code>parser</code> and <code>terminal</code> phases.</a></li>
+
+ <li><a href="#usecase10">Larger compiler example with three
+ plug-in supplied phases.</a></li>
+
+
+ </ol>
+
+ <a name="detailedusecases"></a>
+ <h3>Detailed Use Cases</h3>
+
+ <a name="usecase1"></a>
+ <h4>[1] Assembling compiler internal phases for the JVM target and
+ no plug-ins are loaded.</h4>
+
+ <p>All phases have to declare a <code>runsAfter</code> list of phase
+ names that should be run before the phase itself in the final
+ compiler phase chain. In this use case there are no plug-in supplied
+ phases, that have to be included. Depending on the command line
+ options and the JVM target the for this target default phases are
+ added to the phases set. This is a set, because a phase may only
+ occur once in the compiler phase chain.</p>
+
+ <p>Following these basic <code>runsAfter</code> constraints the
+ compiler phase chain is build from the phases set. In the example
+ below a simple set of phase constraints can be converted into a
+ graph, that in turn can be converted into a list of phases.
+ </p>
+ <div style="text-align: center;">
+ <img src="sip-00002-1.png" alt="" border="0" width="100%" height="" />
+ </div>
+
+ <p>Using the <code>runsAfter</code> list as the basic ordering
+ constraints there are some more properties that have to be
+ full filled.
+ </p>
+ <ul>
+ <li>The phases <code>liftcode</code> and <code>flatten</code> are
+ only included for the JVM target. They have <code>runsAfter</code>
+ dependencies on the <code>refchecks</code> phase and the
+ <code>constructors</code> phase, respectively. Because they are
+ only included in the JVM target the <code>uncurry</code> phase and
+ the <code>mixin</code> phase, respectively, need to have multiple
+ dependencies as seen in the example below.
+
+ <p>This example shows the desired transformation steps of a small
+ dependency graph taken from the actual compiler phase graph. When
+ processing <code>refchecks</code> we notice that it has two
+ dependencies to it. One dependency comes from
+ <code>liftcode</code> and the other from <code>uncurry</code>. We
+ now look if any of these phases have more then one outgoing
+ dependency. The <code>liftcode</code> phase has one outgoing
+ dependency, but the <code>uncurry</code> phase has two, so one of
+ the outgoing dependencies of <code>uncurry</code> has to go to
+ <code>refchecks</code> and the other dependency has to go to some
+ place we have not visited yet. So by this reasoning, we can safely
+ remove the dependency from <code>uncurry</code> to
+ <code>refchecks</code> (marked red).</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-21.png" alt="" border="0" width="85%" height="" />
+ </div>
+ <p></p>
+ </li>
+
+ <li>Some internal phase pairs have very strong dependencies, like
+ the phases <code>explicitouter</code> and <code>erasure</code> and
+ also the <code>namer</code> and <code>typer</code> phases. See <a
+ href="#usecase7">use case 7</a> for more information on this
+ problem.</li>
+ </ul>
+
+
+ <a name="usecase2"></a>
+ <h4>[2] Assembling compiler internal phases for the MSIL target and
+ no plug-ins are loaded.</h4>
+
+ <p>Like in <a href="usecase1">use case 1</a> depending on command
+ line options and that the target being MSIL, the proper phases are
+ added to the phases set. Again there are no plug-in supplied phases
+ to be included. There are however some differences to use case 1.
+ </p>
+ <ul>
+ <li>The phases <code>liftcode</code> and <code>flatten</code> are
+ not included for the MSIL target. This makes the
+ <code>runsAfter</code> list of the phases <code>uncurry</code> and
+ <code>mixer</code> special by containing dependencies to phases
+ that are found in the phases set.
+
+ <p>For instance the <code>uncurry</code> phase has to specify that
+ it wants to run after both <code>refchecks</code> and
+ <code>liftcode</code>. <i>(For the JVM target this will force the
+ <code>liftcode</code> phase before <code>uncurry</code>.)</i> For
+ the MSIL target the phase <code>liftcode</code> is not present as
+ shown in the example diagram below. One solution that will work is
+ to silently drop all dependencies to phases, where there was no
+ phase object in the phases set.</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-22.png" alt="" border="0" width="55%" height="" />
+ </div>
+ </li>
+ </ul>
+
+
+
+ <a name="usecase3"></a>
+ <h4>[3] Adding one plug-in supplied phase to the JVM target
+ compiler after type checking.</h4>
+
+ <p>Like in <a href="#usecase1">use case 1</a> the internal phases
+ are added to the phases set. In this use case a plug-in is loaded
+ that will supply one phase to the phases set with a constraint that
+ it wants to run after the <code>refchecks</code> phase. The original
+ plug-in handling code will still handle loading plug-ins, disabling
+ plug-ins, but will no longer have the responsibility of assembling
+ the compiler chain. The plug-in is loaded and the phase is added
+ to the phases set together with the internal phases.</p>
+ <p>When assembling the compiler phase chain in this use case, there
+ will be two phases directly after the <code>refchecks</code> phase
+ and the dependencies can not be removed as described in <a
+ href="#usecasee1">use case 1</a>. This situation is shown in the
+ example below.</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-2.png" alt="" border="0" width="100%" height="" />
+ </div>
+
+ <p>One of the goals of this proposal is to be as compatible with the
+ current behavior of the compiler as possible. So if the situation is
+ as shown above that after including A, we can either take B or R, we
+ need a deterministic scheme for always constructing the same phase
+ chain. This is done by taking the plug-in supplied phases first and
+ then the internal phase after wards.
+ </p>
+
+
+
+ <a name="usecase4"></a>
+ <h4>[4] Adding two plug-in supplied phase to the JVM target
+ compiler after type checking.</h4>
+
+ <p>This use case is very similar to <a href="#usecase3">use case
+ 3</a>, however instead of having one internal and one external phase
+ after the <code>refchecks</code> phase, we have one internal and two
+ external phases after the <code>refchecks</code> phase. This
+ situation is shown in the example below.</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-23.png" alt="" border="0" width="100%" height="" />
+ </div>
+
+ <p>To be able to deterministically create the compiler phase chain
+ we need a rule to handle multiple external phases at the same
+ level. The simplest rule it to include the external phases
+ alphabetically order, as shown in the example above.</p>
+
+
+ <a name="usecase5"></a>
+ <h4>[5] Adding two plug-in supplied phases, where one has a
+ dependency on the other, to the JVM target compiler.</h4>
+
+ <p>This use case is very similar to <a href="#usecase4">use case
+ 4</a>, however instead of the two plug-in supplied phases having a
+ dependency on the same internal, one of the plug-in supplied phases
+ has a dependency on the other and the other has a dependency on an
+ internal phase. This is the example shown in the diagram below.</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-3.png" alt="" border="0" width="100%" height="" />
+ </div>
+
+ <p>As described in <a href="#usecase3">use case 3</a>, after
+ inclusion of phase A the next phase to include is phase T. In the
+ example above phase R is dependent on phase T, so the next to
+ include is phase R. This means that including phase T, means to
+ include T and the ordered sub tree, under phase T.</p>
+
+ <p>The example shown below, can be solved applying the same logic as
+ described above.</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-4.png" alt="" border="0" width="100%" height="" />
+ </div>
+
+
+ <a name="usecase6"></a>
+ <h4>[6] Adding plug-in supplied phases with dependencies to both
+ plug-in supplied and internal phases to the JVM target
+ compiler.</h4>
+
+ <p>This use case builds upon <a href="#usecase1">use case 1</a>, <a
+ href="#usecase3">use case 3</a>, <a href="#usecase4">use case 4</a>
+ and <a href="#usecase5">use case 5</a> and shows how to handle
+ plug-in supplied phases with dependencies on other plug-in supplied
+ and internal phases.</p>
+
+ <p>In the example shown below the plug-in supplied phase T has
+ dependencies on the plug-in supplied phase P and the internal phase
+ B. The transformation shown below is made by applying the logic from
+ <a href="#usecase1">use case 1</a> to this example and using the
+ assumption that the dependencies of the internal phases will not
+ contain cycles and internal phases are visited last on each
+ level.</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-5.png" alt="" border="0" width="100%" height="" />
+ </div>
+
+ <a name="usecase7"></a>
+ <h4>[7] Two separate phases that should be handled as a single
+ phase.</h4>
+
+ <p>In <a href="#usecase1">use case 1</a> we specified the assembly
+ of the compiler phase chain based on runs after
+ constraints. However, the compiler contains some phase pairs that
+ have very strong dependencies on each other or it simply does not
+ make sense to put a phase in between. In this use case we will focus
+ on the situation that we have two individual phase objects, but one
+ needs to run right after the other and thereby act as one large
+ phase.</p>
+
+ <p>The solution to this is to introduce a new runs right after
+ constraint to all phases. To keep the compatibility with current
+ plug-ins as high as possible, this runs right after constraint is
+ only mandatory for internal phases. In the example below the
+ <code>runsRightAfter</code> constraint is marked as a blue arrow and
+ behaves as a normal runs after constraint.
+ </p>
+ <div style="text-align: center;">
+ <img src="sip-00002-7.png" alt="" border="0" width="100%" height="" />
+ </div>
+
+ <p>In the example shown below, we can see the first four phases of
+ the Scala compiler. There is a <code>runsRightAfter</code>
+ constraint between <code>typer</code> and <code>namer</code>. There
+ is in this example a plug-in supplied phase (plugin1) that want to
+ run after the <code>namer</code> phase. The semantics of the run
+ after constraint is that is should run somewhere after a specified
+ phase, but as soon as possible. With this in mind it is perfectly
+ valid to change the dependency of <code>plugin1</code> from
+ <code>namer</code> to <code>typer</code>. </p>
+ <div style="text-align: center;">
+ <img src="sip-00002-8.png" alt="" border="0" width="100%" height="" />
+ </div>
+
+ <p>If the phase <code>plugin1</code> had declared to
+ <code>runRightAfter</code> the <code>namer</code> phase, this would
+ result in a unsolvable graph and would therefore generate an error,
+ because only one phase can come right after another phase.
+ </p>
+
+ <a name="usecase8"></a>
+ <h4>[8] A cyclic dependency among phases is a fatal error.</h4>
+
+ <p>Running the compiler without loading plug-ins, it is guaranteed
+ that there are do cyclic dependencies among the internal phases, so
+ the only way to introduce cycles in the phase graph is by loading
+ one or more plug-ins. If a cycle is detected in the phase graph the
+ compiler should refuse to start and give a proper error message.</p>
+
+ <p>In the example shown below a cycle is detected and marked in
+ pink. A cycle like this would generate a cyclic dependency error and
+ outputting the names of the involved phases.</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-20.png" alt="" border="0" width="35%" />
+ </div>
+
+ <a name="usecase9"></a>
+ <h4>[9] Special handling of the <code>parser</code> and
+ <code>terminal</code> phases.</h4>
+
+ <p>There are two very special phase objects in the phase graph. The
+ first phase is the <code>parser</code> phase. This phase will be the
+ head of the compiler phase chain, there are however no other
+ restrictions on this phase.</p>
+
+ <p>The other special phase is the <code>terminal</code> phase, which
+ has to be the last phase in the compiler phase chain. For this
+ reason it is not allowed to run after or run right after the
+ <code>terminal</code> phase. Any phase that specifies a runs after
+ or runs right after dependency on the <code>terminal</code> phase
+ will have that dependency dropped silently.</p>
+
+
+ <a name="usecase10"></a>
+ <h4>[10] Larger compiler example with three plug-in supplied phases.</h4>
+
+ <p>This example is implemented in the <a
+ href="#implementation">reference implementation</a> of the algorithm
+ below. In this example the compiler consists of nine internal phases
+ and two plug-ins are loaded adding a total of three phases to the
+ compiler.
+ </p>
+
+ <table width="100%" border="1">
+ <tr>
+ <td><strong>Phase name</strong></td>
+ <td><strong>Runs after</strong></td>
+ <td><strong>Runs right after</strong></td>
+ </tr>
+ <tr>
+ <td colspan="3" align="center"><strong><i>Internal phases</i></strong></td>
+ </tr>
+ <tr>
+ <td>nsc::parser</td>
+ <td></td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>nsc::typer</td>
+ <td>nsc::parser</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>nsc::pickler</td>
+ <td>nsc::typer</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>nsc::liftcode</td>
+ <td>nsc::pickler</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>nsc::tailcalls</td>
+ <td>nsc::pickler<br />nsc::liftcode</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>nsc::erasure</td>
+ <td></td>
+ <td>nsc::tailcalls</td>
+ </tr>
+ <tr>
+ <td>nsc::cleanup</td>
+ <td>nsc::erasure</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>nsc::jvm</td>
+ <td>nsc::cleanup</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>nsc::terminal</td>
+ <td>nsc::jvm<br />nsc::msil</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td colspan="3" align="center"><strong><i>Plug-in supplied phases</i></strong></td>
+ </tr>
+ <tr>
+ <td>plug1::optimization1</td>
+ <td>nsc::typer</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>plug2::optimization1</td>
+ <td>nsc::liftcode</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>plug2::optimization2</td>
+ <td>plug2::optimization1<br />nsc::cleanup</td>
+ <td></td>
+ </tr>
+ </table>
+
+ <p>Using the phases in the table above as the basis for the
+ dependency graph, the following graph will be constructed. This
+ graph contains all the information that is also present in the
+ phases set. As seen in the diagram below there are nodes without
+ phase objects (marked with dotted lines) and nodes with multiple
+ dependencies. There could also be cycles at this stage, but there
+ are non in this example.
+ </p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-6.png" alt="" border="0" width="60%" height="" />
+ </div>
+
+ <p>The transformation of the dependency graph into a dependency tree
+ is the basis of this proposal. The resulting dependency tree is
+ shown below. This tree is then the basis for generating the compiler
+ phase list.
+ </p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-24.png" alt="" border="0" width="60%" height="" />
+ </div>
+
+ <p>The resulting compiler phase list of traversing the tree above is
+ shown below. It is ensured that the <code>parser</code> phase is the
+ first and that the <code>terminal</code> phase is the last in this list.</p>
+
+ <ul>
+ <li>nsc::parser</li>
+ <li>nsc::typer</li>
+ <li>plug1::optimization1</li>
+ <li>nsc::pickler</li>
+ <li>nsc::liftcode</li>
+ <li>plug2::optimization1</li>
+ <li>nsc::tailcalls</li>
+ <li>nsc::erasure</li>
+ <li>nsc::cleanup</li>
+ <li>plug2::optimization2</li>
+ <li>nsc::jvm</li>
+ <li>nsc::terminal</li>
+ </ul>
+
+ <a name="futuregoals"></a>
+ <h3>Future Goals That Extend Beyond This Proposal</h3>
+
+ <ul>
+ <li>Create and add new backends to the compiler that will replace
+ the JVM or MSIL specific phases using plug-ins.</li>
+ <li>Creating internal tools by subclassing the class
+ <code>Global</code>.</li>
+ <li>The constraint system should not contain support for the
+ following constraints.
+ <ul>
+ <li>A phase should be able to declare that it will replace a
+ given phase and thereby ignoring other constraints declared by
+ this phase and taking over the constraints from the replaced
+ phase.</li>
+ <li>A phase should be able to declare that if included it will
+ remove a given number of phases and removing constraints to
+ these phases.</li>
+ <li>A phase should be able to declare that it only wants to be
+ included if a given phase is also present or else it will be
+ silently dropped.</li>
+ </ul>
+ </li>
+ </ul>
+
+ <a href="#top">To the top</a>
+
+ <a name="description"></a>
+ <h2>Description</h2>
+
+ <p>This section will cover a short description of the present design
+ and the full description of the proposed design changes, including
+ the constraint system and algorithm for solving the constraint
+ system.
+ </p>
+
+ <a name="presentdesign"></a>
+ <h3>The Present Design</h3>
+
+ <p>Currently phases in the compiler are ordered statically by a hard
+ coded list structure in <code>class Global</code> (found in
+ Global.scala), where the method <code>builtInPhaseDescriptors</code>
+ returns the list of phase objects. The resulting list from invoking
+ this method is then extended with the phases from the plug-in
+ supplied by the user. This is done in the
+ <code>computePhaseDescriptors</code> method in <code>class
+ Plugins</code> (found in plugins/Plugins.scala). This method is
+ then again called from the method <code>phaseDescriptors</code> in
+ <code>class Global</code>. So all together the process of
+ calculating the phases of the compiler is spread over several files
+ and quite complicated.</p>
+
+ <p>A plug-in can supply a number of phases to the compiler and the
+ architecture of the plug-in subsystem already supply some of the
+ functionality that will be added to all internal phases. All phases
+ are a subclass of <code>class SubComponent</code> and all phases
+ supplied by plug-ins are subclasses of <code>class
+ PluginComponent</code> (which is a subclass of <code>class
+ SubComponent</code>).</p>
+
+ <a name="proposeddesign"></a>
+ <h3>The Proposed Design</h3>
+
+ <p>This section will cover the design of the proposed system for
+ handling inclusion of internal and external phases uniformly. It
+ will also cover a description of the constraint system and a
+ algorithm for solving these constraint for generating the compiler
+ phase chain. This design will focus on satisfying the use cases <a
+ href="#usecases">described earlier</a>.
+ </p>
+
+ <p>From the use cases above it is possible to identify two kinds of
+ constraints. The first constraint is the <i>runs after</i>
+ dependency and the second constraint is the <i>runs right after</i>
+ dependency. It is necessary to declare that a given phase has to
+ <i>runs after</i> a list of phase names, however the <i>runs right
+ after</i> constraint only needs to declare the name one phase.
+ </p>
+ <ul>
+ <li>Lets define the <i>runs after</i> constraint using the
+ <code>runsAfter</code> variable with the Scala type
+ <code>List[String]</code>. Using this constraint, phase B would
+ declare <code>runsAfter=List(A)</code>, meaning that phase B would
+ like to run somewhere after phase A, but as early as possible.</li>
+
+ <li>Lets define the <i>runs right after</i> constraint using the
+ <code>runsRightAfter</code> variable with the Scala type
+ <code>Option[String]</code>. Using this constraint, phase B would
+ declare <code>runsRightAfter=Some(A)</code>, meaning that phase B
+ wants to run right after phase A and no other phases are allowed to
+ come between phase A and B. From a larger perspective meaning that
+ phase A and B can be regarded as on large phase with one input and
+ one output.</li>
+ </ul>
+
+ <p>A goal of this work is to handle the inclusion and constraint
+ resolution of internal and plug-in supplied phases in a uniform way,
+ this also means that the responsibility of phase assembly should not
+ be handled by the plug-in subsystem any more, but by a separate
+ instance. For this separate instance we create a new
+ <code>PhaseAssembly</code> trait that is mixed into the
+ <code>Global</code> class in the same way as <code>Plug-Ins</code>
+ is mixed in.
+ </p>
+
+ <p>In the diagram below a schematic overview of the proposed system
+ is shown. A description of the individual components and the
+ modification needed are given below.
+ </p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-9.png" alt="" border="0" width="55%" />
+ </div>
+
+ <a name="propdesign1"></a>
+ <h4>1. Internal Phases</h4>
+
+ <p>All internal phase objects are declared in class
+ <code>Global</code> and will be extended to include the
+ <code>runsAfter</code> and the <code>runsRightAfter</code> variables
+ with the types described above. This will ensure that the internal
+ phases will always succeed in creating a compiler phase chain
+ depending on the compiler target.
+ </p>
+ <p>The phase objects that are needed for a given target will be
+ added to the phases set. See <a href="#propdesign3">3. Phases
+ Set</a> for more information.
+ </p>
+
+
+ <a name="propdesign2"></a>
+ <h4>2. External Phases</h4>
+
+ <p>All external phases are supplied through plug-ins. All these
+ phases inherit from class <code>PluginComponent</code>. Defining the
+ <code>runsRightAfter=None</code> in class
+ <code>PluginComponent</code> will make the changes to the existing
+ plug-ins minimal, but makes it possible for external phases to use
+ the feature by simple overriding the variable if needed.
+ </p>
+ <p>It is still the responsibility of the plug-in subsystem to load
+ the actual plug-ins from the jar files and also the processing of
+ all the <code>-Xplugin*</code> compiler options available at the
+ command line. The phase assembly code currently present in the
+ plug-in subsystem will be replaced by code that adds all plug-in
+ supplied phases to the phases set. See <a
+ href="#propdesign3">3. Phases Set</a> for more information.
+ </p>
+
+ <a name="propdesign3"></a>
+ <h4>3. Phases Set</h4>
+
+ <p>The phases set contains all the phase objects that should be
+ taken into consideration when performing compiler phase chain
+ assembly. This phases set would located in the class
+ <code>Global</code>. A proper Scala declaration of such a phases set
+ is shown below.
+ </p>
+ <pre>protected val phasesSet : HashSet[SubComponent] = new HashSet[SubComponent]()</pre>
+
+ <p>Ensuring that all phase objects are unique with respect to the
+ phase names, the <code>hashCode</code> method in class
+ <code>SubComponent</code> will be overridden to return the hash code
+ of the phase name and not the object itself.
+ </p>
+
+ <a name="propdesign4"></a>
+ <h4>4. Phase Assembly</h4>
+
+ <p>From a compiler design perspective this component will include
+ the data structures and implementation of the constraint solving
+ algorithm that are needed to implement this proposal. It would be
+ integrated as a <code>trait PhaseAssembly</code> that is mixed into
+ <code>class Global</code> with this self type <code>self: Global
+ =&gt;</code>.
+ </p>
+
+ <p>A very high level description of the actions performed by this
+ component can be split into three distinct parts. A detailed
+ algorithm that implements this high level description can be found
+ below in the <a href="#constsolver">section on the constraint
+ solving algorithm</a>.
+ </p>
+
+ <ol>
+ <li><strong>Phases Set to Dependency Graph</strong><br />
+ <p>From the phase objects in the phases set a dependency graph is
+ created, where the edges in this graph are constructed from the
+ <code>runsAfter</code> and <code>runsRightAfter</code>
+ constraints. Each node in the dependency graph has both a phase
+ name and a phase object, because all constraints in the phase
+ objects are only given by name.
+ </p>
+ </li>
+ <li><strong>Dependency Graph to Dependency Tree</strong><br />
+ <p>To be able to create the compiler phase chain the dependency
+ graph has to be converted into a dependency tree. The dependency
+ graph contains nodes that have a phase name, but no phase
+ object. These nodes have to be removed. Also all edges in the
+ graph that are generated from <code>runsRightAfter</code>
+ constraints have to be handled special to enforce this constraint
+ and the graph is checked for cycles. If a cycle is found, the
+ algorithm will terminal with a fatal error, preventing the
+ compiler from starting. If no cycles are found in the dependency
+ graph is simplified with respect to what will become the root in
+ the dependency tree, by removing unneeded dependency edges. This
+ will transform the dependency graph into a dependency tree.
+ </p>
+ </li>
+ <li><strong>Dependency Tree to Compiler Phase List</strong><br />
+ <p>The compiler phase list is constructed by traversing the
+ dependency tree from the root. The traversal algorithm will be
+ described below.
+ </p>
+ </li>
+ </ol>
+
+
+ <a name="propdesign5"></a>
+ <h4>5. Constraint System</h4>
+
+ <p>The constraint system is implemented as a graph structure where
+ phases are modeled as nodes and the constraints are modeled as
+ directed edges. This section will describe the basic entities of the
+ constraint system and how they are modeled in the dependency graph.</p>
+ <table>
+ <tr>
+ <td colspan="2">
+ <p>Each node in the dependency graph contains several items of
+ information about the phase object and the dependencies to and
+ from it.</p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <ul>
+ <li><strong>phaseobj:</strong> <i>(type:
+ SubComponent)</i><br /> A reference to the actual phase
+ object, if there is any. If there is a phase object then
+ there is also a phase name, but the constraints are only
+ given by name, so some nodes may have a phase name and no
+ phase object.
+ </li>
+ <li><strong>phasename:</strong> <i>(type: String)</i><br />
+ The name of the phase object. This is always set.
+ </li>
+ <li><strong>after:</strong> <i>(type: HashSet[Edge]())</i>
+ <br />
+ This is the set of <code>Edge</code> object that point to
+ <code>Node</code> objects that have to come before this
+ <code>Node</code>. So all <code>runsAfter</code> and
+ <code>runsRightAfter</code> constraints given by a phase
+ object are present in this <code>after</code> list.
+ </li>
+ <li><strong>deps:</strong> <i>(type: HashSet[Edge]())</i>
+ <br />
+ This is the set of <code>Edge</code> object that points to
+ this <code>Node</code> object. So its the opposite of the
+ <code>after</code> list.
+ </li>
+ </ul>
+ </td>
+ <td>
+ <div style="text-align: center;">
+ <img src="sip-00002-15.png" alt="" border="0" width="235" height="186" />
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <p>Each edge in the dependency graph is directed, so it has
+ references to its to and from <code>Node</code> objects and
+ knows if it is created from a <code>runsAfter</code>
+ constraint (soft) or created from a
+ <code>runsRightAfter</code> constraint (hard). </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <ul>
+ <li><strong>to:</strong> <i>(type: Node)</i>
+ <br />
+ This is a reference to the <code>Node</code> object this
+ <code>Edge</code> object is pointing to. This means that the
+ <code>frm</code> node has a dependency on the
+ <code>to</code> node.
+ </li>
+ <li><strong>frm:</strong> <i>(type: Node)</i>
+ <br />
+ This is a reference to the <code>Node</code> object this
+ <code>Edge</code> object is pointing from.
+ </li>
+ <li><strong>hard:</strong> <i>(type: Boolean)</i>
+ <br />
+ In the dependency graph we have soft and hard
+ dependencies. The soft dependencies are created from the
+ <code>runsAfter</code> list of constraints. The hard
+ dependencies are created from the
+ <code>runsRightAfter</code> constraint, if any.
+ </li>
+ </ul>
+ </td>
+ <td>
+ <div style="text-align: center;">
+ <img src="sip-00002-16.png" alt="" border="0" width="152" height="186" />
+ </div>
+ </td>
+ </tr>
+ </table>
+
+ <p>Below is the interface implementation of the dependency graph in
+ Scala. There are classes implementing the edges and nodes and the
+ container for storing the edges and nodes and aux. method for easy
+ access to the stored information.
+ </p>
+ <pre>
+class Edge(f: Node, t: Node, h: Boolean) {
+ var frm = f
+ var to = t
+ var hard = h
+}
+
+class Node(phs:SubComponent, name:String) {
+ var phasename: String = name
+ var phaseobj: SubComponent = phs
+ var after: HashSet[Edge] = new HashSet[Edge]()
+ var deps: HashSet[Edge] = new HashSet[Edge]()
+}
+
+class DependencyGraph {
+
+ val nodes = new HashMap[String,Node]()
+ val edges = new HashSet[Edge]()
+
+ def getNodeByPhase(name : String) : Node
+ def getNodeByPhase(phs : SubComponent) : Node
+ def softConnectNodes(frm: Node, to: Node) : Unit
+ def hardConnectNodes(frm: Node, to: Node) : Unit
+}
+ </pre>
+
+
+ <a name="constsolver"></a>
+ <h4>Constraint Solving Algorithm</h4>
+
+ <p>This algorithm will build a list of phase objects from a set of
+ phase objects with constraints. The position of each phase object in
+ the final list will ensure that all its constraints are
+ satisfied. The algorithm does this by constructing a dependency
+ graph from the set of phase objects. This dependency graph is then
+ over a series of steps converted into a dependency tree with a root
+ node. To construct the final compiler phase list the dependency tree
+ is traversed from the root building the list of phase objects.</p>
+
+ <p>The function below is the top most function of this algorithm
+ that transforms the set of phase objects into a ordered list of
+ phase objects so all constraints are satisfied. This function
+ follows the description given about the <a href="#propdesign4">phase
+ assembly component</a>. All the auxiliary functions will be covered
+ below.</p>
+
+<pre> <b>function</b> phasesSetToPhasesList(phasesSet)
+
+ <i>// call function to generate dependency graph from phases set</i>
+ graph &lt;- phasesSetToDepGraph( phaseSet )
+
+ <i>// call function to transform the dependency graph to a dependency tree.</i>
+ <i>// if the dependency graph contains a cycle a fatal error will be generated.</i>
+ rootnode &lt;- depGraphToDepTree( graph )
+
+ <i>// call function to recursively build phase list from the root of </i>
+ <i>// the dependency tree</i>
+ phaselist &lt;- depTreeToPhaseList( rootnode, <b>new</b> List() )
+
+ <b>return</b> phaselist
+</pre>
+
+ <p> List of functions called:</p>
+ <ul>
+ <li><a href="#func1">The <code>phasesSetToDepGraph</code> function</a></li>
+ <li><a href="#func2">The <code>depGraphToDepTree</code> function</a></li>
+ <li><a href="#func3">The <code>depTreeToPhaseList</code> function</a></li>
+ </ul>
+
+ <a name="func1"></a>
+ <h5>The <code>phasesSetToDepGraph</code> function</h5>
+
+ <p>The dependency graph, with the elements described in the <a
+ href="#propdesign5">section about the constraint system</a>, is
+ build from the phase objects in the phases set.<br />
+ It works as follows:
+ </p>
+ <ul>
+ <li>create a new dependency graph</li>
+ <li>foreach phase in the phasesSet
+ <ul>
+ <li>create a new graph node <i>fromnode</i> from the phase object and add the
+ ndoe to the graph</li>
+ <li>if the phase object has a runs right after constraint, then
+ create a node <i>tonode</i> from the phase name of the constraint and create a
+ hard edge between <i>fromnode</i> and <i>tonode</i>. Eventual
+ runs after constraints are ignored.</li>
+ <li>if the phase object has no runs right after constraints a
+ node <i>tonode</i> is created from each runs after constraint
+ and connected with a soft edge to the <i>fromnode</i>.</li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>A pseudo code version of this algorithm is shown below.</p>
+
+<pre> <b>function</b> phasesSetToDepGraph( phaseSet )
+ <i>// create new graph structure to hold data</i>
+ graph &lt;- <b>new</b> DependencyGraph
+ <i>// iterate over all phase objects in the phasesSet</i>
+ <b>for</b> phs <b>in</b> phasesSet
+ <i>// create a node from the phase object</i>
+ fromnode &lt;- graph.getNodeByName(phs)
+ <i>// test if the phase object has a runs right after constraint</i>
+ <b>if</b> phs.runRightAfter <b>not eq</b> ""
+ <i>// create a node from the phase constraint name and connect with hard edge</i>
+ tonode &lt;- graph.getNodeByName( phs.runRightAfter )
+ graph.hardConnectNodes( fromnode, tonode )
+ <b>else</b>
+ <i>// the phase object did not have a runs right after constraint</i>
+ <i>// iterate over all phase constraints in the runs after constraint list</i>
+ <b>for</b> phsname <b>in</b> phs.runsAfter
+ <i>// create a node from the phase constraint name and connect with soft edge</i>
+ tonode &lt;- graph.getNodeByName( phsname )
+ graph.softConnectNodes( fromnode, tonode )
+
+ <b>return</b> graph
+</pre>
+
+
+
+ <a name="func2"></a>
+ <h5>The <code>depGraphToDepTree</code> function</h5>
+
+ <p>The process of converting the dependency graph into a dependency
+ tree is complex, so to simplify the algorithm the individual steps
+ are split into functions.<br />
+ It works as follows:
+ </p>
+
+ <ul>
+ <li>call method that will remove all nodes from the graph that
+ have no phase object attached</li>
+ <li>call method that will find all edges in the graph that are
+ marked as hard and enforce that the <code>deps</code> list of the
+ edges <code>to</code> node reference only contains this
+ edge. Other edges are moved down to the edges <code>frm</code>
+ node reference</li>
+ <li>What is to become the root of the dependency tree and also the
+ first element in the phase list is extracted from the graph.</li>
+ <li>call method to check if there are cycles in the graph starting
+ from the root node, if there are cycles a fatal error is generated</li>
+ <li>call method to simplify graph into a tree by removing edges
+ that will not break the constraints given</li>
+ </ul>
+
+ <p>Below is shown a pseudo code version of the function.</p>
+
+ <pre> <b>function</b> depGraphToDepTree( graph )
+
+ <i>// Remove all nodes where phaseobj == null</i>
+ removeDanglingNodes( graph )
+
+ <i>// Enforce hardlinks / runsRightAfter and promote nodes down the tree</i>
+ enforceHardlinks( graph )
+
+ <i>// Extract the root node from the graph</i>
+ root &lt;- graph.getNodeByPhase( ROOTNAME )
+
+ <i>// Test for cycles in the graph, if found generate fatal error</i>
+ testForCycles( root, <b>new</b> Set() )
+
+ <i>// Simplify graph by removing edges, starting from the given root node</i>
+ simplifyGraphFromNode( root, graph )
+
+ <b>return</b> root
+ </pre>
+
+ <p> List of functions called:</p>
+ <ul>
+ <li><a href="#func4">Helper function <code>removeDanglingNodes</code></a></li>
+ <li><a href="#func5">Helper function <code>enforceHardlinks</code></a></li>
+ <li><a href="#func6">Helper function <code>testForCycles</code></a></li>
+ <li><a href="#func7">Helper function <code>simplifyGraphFromNode</code></a></li>
+ </ul>
+
+ <a name="func3"></a>
+ <h5>The <code>depTreeToPhaseList</code> function</h5>
+
+ <p>The graph has been transformed into a tree and a reference to the
+ root node is identified. The tree is now traversed from the root
+ node, by calling itself recursively on each node object. The empty
+ list is given to the function together with the root node and the
+ phase objects are added to the list as the function traverses the
+ tree.<br />
+ It works as follows:</p>
+
+ <ul>
+ <li>the function is called with a node object and a list</li>
+ <li>the phase object of the node object, the function was call
+ with, is added to the list</li>
+ <li>if this node has no nodes that depend on it, the list of phase
+ objects is returned</li>
+ <li>if this node has only one node that depends on it, we call
+ recursively with that node and the list as arguments, the result
+ of this is returned</li>
+ <li>if this node has more then one node that depends upon it,
+ these dependent nodes are ordered. We now iterate over this
+ ordered list of nodes and call recursively the function.</li>
+ </ul>
+
+ <p>Below is shown a pseudo code version of the function.</p>
+
+ <pre> <b>function</b> depTreeToPhaseList( node, chain )
+ <i>// add the phase object of the node to the chain list</i>
+ chain &lt;- chain.append( node.phaseobj )
+ <i>// no more depends, return the chain</i>
+ <b>if</b> node.deps.length == 0
+ <b>return</b> chain
+ <i>// only one depend, so no need to order one element, just call recursively </i>
+ <b>else if</b> node.deps.length == 1
+ <b>return</b> depTreeToPhaseList( node.deps.getFirst().frm, chain )
+ <i>// more then one depend</i>
+ <b>else</b>
+ <i>// the depends are ordered and saved as a list</i>
+ order &lt;- dependencyOrder( node.deps )
+ <i>// iterate over the list of ordered depend nodes and call recursively </i>
+ <b>for</b> nd <b>in</b> order
+ chain &lt;- depTreeToPhaseList( nd, chain )
+ <i>// return the complete chain</i>
+ return chain
+ </pre>
+
+ <p> List of functions called:</p>
+ <ul>
+ <li><a href="#func8">Helper function <code>dependencyOrder</code></a></li>
+ </ul>
+
+ <a name="func4"></a>
+ <h5>Helper function <code>removeDanglingNodes</code></h5>
+
+ <p>This helper function will given a dependency graph find all nodes
+ that have no reference to a phase object and remove these nodes from
+ the graph. (See <a href="#usecase2">use caes 2</a>) These nodes that
+ have no phase object are generated from runs after or runs right
+ after constraints to phases that are not loaded.<br /> It is done as
+ follows:</p>
+
+ <ul>
+ <li>create a list L of all nodes in the given graph that have no
+ phase object</li>
+ <li>foreach node in L
+ <ul>
+ <li>remove the node from the graph</li>
+ <li>foreach edge in the nodes deps list, remove this edge from
+ the graph</li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>Below is shown a pseudo code version of the function.</p>
+
+ <pre> <b>function</b> removeDanglingNodes( graph )
+ <i>// find all nodes with no phase object</i>
+ dnodes &lt;- filter( lambda node: node.phaseobj == null, graph.nodes )
+ <i>// iterate over these nodes and remove them one by one</i>
+ <b>for</b> node <b>in</b> dnodes
+ graph.nodes.remove( node )
+ <i>// also remove all edge objects related to this node object</i>
+ <b>for</b> edge <b>in</b> node.deps
+ graph.edges.remove( edge )
+ edge.frm.after.remove( edge )
+ </pre>
+
+
+ <a name="func5"></a>
+ <h5>Helper function <code>enforceHardlinks</code></h5>
+
+ <p>This helper function will given a dependency graph find all edges
+ in the graph that are marked as hard. It will then ensure that the
+ <code>to</code> node the edge is pointing to only has this edge in
+ its deps list. (See <a href="#usecase7">use case 7</a>).<br />
+ It works as follows:
+ </p>
+
+ <ul>
+ <li>loop until no edges are moved
+ <ul>
+ <li>create list L of all edges in the given graph that are marked
+ as hard</li>
+ <li>foreach edge in L
+ <ul>
+ <li>create list HE of edges marked as hard in the deps list of
+ the node object this edge is pointing to</li>
+ <li>if there is more then one element in HE it will not be possible
+ to generate a compiler phase list and a fatal error is
+ generated</li>
+ <li>if there is only one element in HE, create a list E of all
+ the edges not marked as hard in the deps list of
+ the node object this edge is pointing to</li>
+ <li>override the deps list of the node object this edge is
+ pointing to with the HE list</li>
+ <li>foreach pedge in E
+ <ul>
+ <li>attach the pedge to the deps list of the node object this
+ edge is pointing from</li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>Below is shown a pseudo code version of the function.</p>
+
+ <pre> <b>function</b> enforceHardlinks( graph )
+ <b>do</b>
+ <i>// lets assume that no edges are moved until proven otherwise</i>
+ rerun &lt;- <b>false</b>
+ <i>// find all edges in the graph that are marked as hard</i>
+ hardlinks &lt;- <b>filter</b>( <b>lambda</b> e: e.hard, graph.edges )
+ <i>// iterate over all hard edges found</i>
+ <b>for</b> edge <b>in</b> hardlinks
+ <i>// find all hard edges in the deps list of the node this edge points to</i>
+ sanity &lt;- <b>filter</b>( <b>lambda</b> e: e.hard, edge.to.deps )
+ <b>if</b> sanity.length > 1
+ <i>// generate fatal error, there is more then one runs right
+ // after constraint on the same node</i>
+ <b>else</b>
+ <i>// find all non hard edges in the deps list of the node this edge points to</i>
+ promote &lt;- <b>filter</b>( <b>lambda</b> e: not e.hard, edge.to.deps )
+ <i>// assign the list of hard edges to the deps list of the node this
+ // edge points to</i>
+ edge.to.deps &lt;- sanity
+ <i>// iterate over all non hard edges and attach them to the deps list of the
+ // node this edge points from</i>
+ <b>for</b> pedge <b>in</b> promote
+ <i>// we have moved an edge - we need to rerun this to check</i>
+ rerun &lt;- true
+ <i>// move the edge object down along the hard edge</i>
+ pedge.to &lt;- edge.frm
+ edge.frm.deps.attach(pedge)
+ <i>// if edges where moved, then rerun to make sure the structure is valid</i>
+ <b>while</b> rerun
+ </pre>
+
+ <p>To better understand this little function, lets look at some
+ diagrams and how this function works on these examples. The first
+ example is shown below. Here phase B wants to run right after phase
+ A and phase C just wants to run somewhere after phase A, so there is
+ no problem in pushing phase C down to run after phase B. The
+ function does this be first finding all the hard edges (the blue
+ edges). It then inspects the edges one by one and in this example we
+ have only one hard edge. The edge goes from phase B to phase A,
+ meaning that phase B want to run right after phase A. The algorithm
+ now looks at the <code>deps</code> list of phase A and finds that
+ there is only one hard edges (this is very good). The algorithm now
+ filters out the non-hard edges and finds the edge to phase C. This
+ edge is now detached from phase A and attached to phase B.
+ </p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-17.png" alt="" border="0" width="40%" />
+ </div>
+
+ <p>With the same arguments can we also handle the situation shown
+ below.</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-18.png" alt="" border="0" width="45%" />
+ </div>
+
+
+ <a name="func6"></a>
+ <h5>Helper function <code>testForCycles</code></h5>
+
+ <p>This helper function will, given a node in the graph and a set
+ containing node names, determine of there are any cycles in the
+ graph. This will ensure that <a href="#usecase8">use case 8</a> is
+ addressed. Please note that this function will call itself
+ recursively and is called the first time with the root node and an
+ empty set of node names.
+ <br />
+ It is done as follows:
+ </p>
+
+ <ul>
+ <li>test if the name of the node is already contained in the set,
+ if it is a cycle is found and a fatal error is generated.</li>
+ <li>if the name is not in the set, the name of the node is added
+ to the set</li>
+ <li>the deps list of the node is ordered and stored in nodes</li>
+ <li>foreach nd in nodes
+ <ul>
+ <li>call the function recursively with the node nd and the set
+ of node names</li>
+ </ul>
+ </li>
+ <li>remove the name of the node from the set</li>
+ </ul>
+
+ <p>Below is shown a pseudo code version of the function.</p>
+
+ <pre> <b>function</b> testForCycles( node, names )
+ <i>// test if the name of the node is already in the set</i>
+ <b>if</b> names.contains( node.phasename )
+ <i>// names are unique, so this is a fatal error, there is a cycle
+ // the same name has been visited twice</i>
+
+ <i>// add the name of the node to the set</i>
+ names.add( node.phasename )
+ <i>// use the dependencyOrder function to sort the deps of the node</i>
+ nodes &lt;- dependencyOrder( node.deps )
+ <i>// iterate over all deps nodes and call recursively</i>
+ <b>for</b> nd <b>in</b> nodes
+ testForCycles(nd, names)
+
+ <i>// remove the name of the node from the set</i>
+ names.remove( node.phasename )
+ </pre>
+
+ <p> List of functions called:</p>
+ <ul>
+ <li><a href="#func8">Helper function <code>dependencyOrder</code></a></li>
+ </ul>
+
+ <p>There are other ways of detecting cycles in graphs, that are
+ faster and more efficient, please <a
+ href="http://www.cs.umu.se/kurser/TDBA77/VT06/algorithms/BOOK/BOOK2/NODE68.HTM">read
+ here</a> for more information.</p>
+
+ <a name="func7"></a>
+ <h5>Helper function <code>simplifyGraphFromNode</code></h5>
+
+ <p>This helper function will, given a node in the graph and a
+ reference to the graph structure, remove unneeded edges and
+ transforming the graph into a tree. Please note that this
+ function will call itself recursively and is called the first time
+ with the root node and the full graph.
+ <br />
+ It is done as follows:
+ </p>
+
+ <ul>
+ <li>create an empty list RM</li>
+ <li>foreach edge in the deps list of the node, if the node this
+ edge is pointing from has mode then one dependencies then add this
+ edge to RM</li>
+ <li>foreach edge in RM, remove this edge from the graph</li>
+ <li>the deps list of the node is ordered and stored in nodes</li>
+ <li>foreach nd in nodes
+ <ul>
+ <li>call the function recursively with the node nd and the
+ updated graph</li>
+ </ul>
+ </li>
+ </ul>
+
+ <p>Below is shown a pseudo code version of the function.</p>
+
+ <pre> <b>function</b> simplifyGraphFromNode( node, graph )
+ removal &lt;- <b>new</b> List()
+ <b>for</b> edge <b>in</b> node.deps
+ <b>if</b> edge.frm.after.length > 1
+ removal.append( edge )
+
+ <b>for</b> edge <b>in</b> removal
+ node.deps.remove( edge )
+ edge.frm.after.remove( edge )
+ graph.edges.remove( edge )
+
+ nodes &lt;- dependencyOrder( node.deps )
+ <b>for</b> nd <b>in</b> nodes
+ simplifyGraphFromNode( nd, graph )
+ </pre>
+
+ <p> List of functions called:</p>
+ <ul>
+ <li><a href="#func8">Helper function <code>dependencyOrder</code></a></li>
+ </ul>
+
+
+ <p>In the example shown below we simplify this graph into a tree
+ from the node A. This means that we start the traversal from node A
+ and uses the <code>A.deps</code> list to continue the traversal. If
+ <code>A.deps</code> contains more then one element, the list is
+ sorted so we first visit all plug-in supplied phases in alphabetical
+ order and then the internal phase. In this example this gives the
+ order <code>[P,R,B]</code>. Before the algorithm traverses to a new
+ node it checks that node for its number of <code>after</code>
+ links. If it has more then one after link, it simply deletes the
+ link to it so it can carry on. In the example below this is the case
+ of node P and T. When the algorithm visits node P and wants to
+ traverse on to node T, it checks the number of <code>after</code>
+ constraints in node T. Node T has two after constraints so it can
+ safely delete the edge between node P and T, because there must be
+ another node that we have not included yet, that will include this
+ node T.</p>
+
+ <div style="text-align: center;">
+ <img src="sip-00002-19.png" alt="" border="0" width="70%" />
+ </div>
+
+
+ <a name="func8"></a>
+ <h5>Helper function <code>dependencyOrder</code></h5>
+
+ <p>This helper function will given a list of edges sort them
+ according to a specific scheme are return them as a list. The
+ sorting scheme is as follows. The returned list is the reverse of
+ first having the plug-in supplied phases in alphabetical order
+ followed by the internal phases. <br />
+ This is done as follows:
+ </p>
+ <ul>
+ <li>nodes for internal and external phases are filtered from the
+ deps list</li>
+ <li>the external nodes are ordered by the phase name and
+ reversed</li>
+ <li>the external nodes are appended to the internal nodes list and
+ the resulting list is reversed</li>
+ </ul>
+
+ <p>Below is shown a pseudo code version of the function.</p>
+
+ <pre> <b>function</b> dependencyOrder( deps )
+ external &lt;- <b>filter</b>(<b>lambda</b> e: (! e.frm.phaseobj.internal), deps)
+ internal &lt;- <b>filter</b>(<b>lambda</b> e: e.frm.phaseobj.internal, deps)
+
+ extnodes &lt;- <b>map</b>(<b>lambda</b> e: e.frm, external)
+ extnodes &lt;- extnodes.sort(<b>lambda</b> (n1,n2): (n1.phasename compareTo n2.phasename) &lt; 0)
+ extnodes &lt;- extnodes.reverse
+
+ nodes &lt;- (<b>map</b>(<b>lambda</b> e: e.frm, internal)).<b>extend</b>( extnodes )
+ nodes &lt;- nodes.reverse
+ <b>return</b> nodes
+ </pre>
+
+
+
+ <a name="namingscheme"></a>
+ <h3>Naming Scheme for Internal and External Phases</h3>
+
+ <p>Having the ability to load a large number of plug-ins, where each
+ plug-in can supply several named phases, gives a high possibility of
+ name clashes. There is no way to enforce unique names in plug-in
+ supplied phases because they can have inter dependencies. The best
+ solution is to suggest a naming scheme for phase names.</p>
+
+ <p>This naming scheme composes all names from the package/plug-in
+ name, then a double colon <code>::</code> and then the actual phase
+ name. So for the internal compiler phase names this would be:</p>
+
+ <pre> val phaseName = "nsc::tailcalls"</pre>
+
+ <p>For a plug-in with name <code>unit</code> that supplies a phase
+ with name <code>convert</code> the full phase name would be:</p>
+
+ <pre> val phaseName = "unit::convert"</pre>
+
+ <p>By using this naming scheme for all phases there is a namespace
+ for phase names within each plug-in and external phases will never
+ clash with internal phase names.</p>
+
+ <a name="implications"></a>
+ <h3>Implications of This Proposal</h3>
+
+ <p>All plug-ins need to be updated to the design in this
+ proposal. This means that all current plug-ins will not be able to
+ load. However the modifications to the existing plug-ins are
+ minor. Current variables and types:
+ </p>
+ <pre> val runsAfter: String</pre>
+ <p>The proposed changes are:</p>
+ <pre> val runsAfter: List[String]</pre>
+
+ <p>All internal phases in the compiler need to declare there
+ ordering. This means that instead of having the ordering very
+ explicit in the list structure, the ordering is encoded into each
+ phase object. The following signatures will be added to the
+ <code>SubComponent</code> class.</p>
+
+ <pre> val runsAfter: List[String]
+ val runsRightAfter: Option[String]</pre>
+
+ <p>The following items must be added to each phase
+ object to implement the signatures (however they must be adapted to
+ the individual phase object).</p>
+
+ <pre> val runsAfter = List[String]("phasename")
+ val runsRightAfter = None</pre>
+
+ <p>There is no reason to change the names of the phases as suggested in
+ the section above, but it will minimize the chance of name clashes
+ and will also minimize the chance of accidental dependencies.</p>
+
+ <a href="#top">To the top</a>
+
+ <a name="implementation"></a>
+ <h2>Implementation</h2>
+
+ <p>An example implementation has been created that follows the
+ algorithm sketched in this proposal and models the compilers
+ internal structure. This implementation can be found in the file <a
+ href="sip-00002-10.scala">sip-00002-10.scala</a>. The example
+ implementation uses the phases from <a href="#usecase10">use case
+ 10</a> as its data.
+ </p>
+
+ <p>Running the example code</p>
+
+ <ul>
+ <li>Compile the code using <code>scalac
+ sip-00002-10.scala</code></li>
+ <li>Run the example using <code>scala
+ depgraph.DepGraphTest</code></li>
+ <li>This will generate the console output as seen below and <a
+ href="http://www.graphviz.org/">Graphviz</a> dot files that can be
+ compiled into png images. These png images are also shown
+ below.</li>
+ </ul>
+
+ <a name="consoleexample"></a>
+ <p>Console output</p>
+
+ <pre>$ scalac sip-00002-10.scala
+$ scala depgraph.DepGraphTest
+[dropping depend on node with no phase: nsc::msil]
+[removing edge: nsc::tailcalls =&gt; nsc::pickler]
+[removing edge: plug2::optimization2 =&gt; plug2::optimization1]
+ - nsc::parser
+ - nsc::typer
+ - plug1::optimization1
+ - nsc::pickler
+ - nsc::liftcode
+ - plug2::optimization1
+ - nsc::tailcalls
+ - nsc::erasure
+ - nsc::cleanup
+ - plug2::optimization2
+ - nsc::jvm
+ - nsc::terminal
+$ </pre>
+
+ <p>PNG images of the generated dot files showing the graph
+ structure. Internal phases are marked as black circles and plug-in
+ phases are marked as green circles. The hard links (runsRightAfter
+ constraints) are marked as blue arrows. Click on the pictures to
+ enlarge.</p>
+ <a name="examples"></a>
+ <table>
+ <tr>
+ <td valign="top"><strong>1. </strong><br />
+ <div style="text-align: center;">
+ <a href="sip-00002-11.png">
+ <img src="sip-00002-11.png" alt="" border="0" width="100%"/>
+ </a>
+ </div>
+ </td>
+
+ <td valign="top"><strong>2. </strong><br />
+ <div style="text-align: center;">
+ <a href="sip-00002-12.png">
+ <img src="sip-00002-12.png" alt="" border="0" width="100%" />
+ </a>
+ </div>
+ </td>
+ <td valign="top"><strong>3. </strong><br />
+ <div style="text-align: center;">
+ <a href="sip-00002-13.png">
+ <img src="sip-00002-13.png" alt="" border="0" width="100%" />
+ </a>
+ </div>
+ </td>
+ <td valign="top"><strong>4. </strong><br />
+ <div style="text-align: center;">
+ <a href="sip-00002-14.png">
+ <img src="sip-00002-14.png" alt="" border="0" width="100%" />
+ </a>
+ </div>
+ </td>
+ </tr>
+ </table>
+
+ <a href="#top">To the top</a>
+
+</body>
+</html>