changeset 2708:4272b7af2d17

merge
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 18 May 2011 18:40:58 +0200
parents 7ed72769d51a (current diff) 5a784215351a (diff)
children 0efd77a02ea9 a0dd2b907806
files graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java graal/GraalCompiler/src/com/sun/c1x/alloc/ControlFlowOptimizer.java graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java graal/GraalCompiler/src/com/sun/c1x/doc/IRInterpreter.txt graal/GraalCompiler/src/com/sun/c1x/doc/LoopPeeling.txt graal/GraalCompiler/src/com/sun/c1x/doc/backend_open_issues.txt graal/GraalCompiler/src/com/sun/c1x/doc/differences.txt graal/GraalCompiler/src/com/sun/c1x/doc/performance.txt graal/GraalCompiler/src/com/sun/c1x/graph/BlockUtil.java graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java graal/GraalCompiler/src/com/sun/c1x/graph/IR.java graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java graal/GraalCompiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java graal/GraalCompiler/src/com/sun/c1x/lir/LIRAssembler.java graal/GraalCompiler/src/com/sun/c1x/lir/LIRBlock.java graal/GraalCompiler/src/com/sun/c1x/lir/LIRList.java graal/GraalCompiler/src/com/sun/c1x/lir/LIRStackAllocate.java graal/GraalCompiler/src/com/sun/c1x/opt/InstructionSubstituter.java graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java graal/GraalCompiler/src/com/sun/c1x/target/sparc/SPARC.java graal/GraalGraphviz/src/com/oracle/graal/graph/vis/GraphvizPrinter.java
diffstat 47 files changed, 986 insertions(+), 1482 deletions(-) [+]
line wrap: on
line diff
Binary file doc/design/graal_compiler.pdf has changed
--- a/doc/design/graal_compiler.tex	Wed May 18 18:09:20 2011 +0200
+++ b/doc/design/graal_compiler.tex	Wed May 18 18:40:58 2011 +0200
@@ -1,4 +1,5 @@
 \documentclass[twocolumn]{svjour3}
+\usepackage{listings}
 \usepackage[pdftex]{graphicx}
 \usepackage{environ}
 \usepackage{amsmath}
@@ -53,7 +54,7 @@
 \maketitle
 
 \abstract{
-The Graal compiler (simply referred to as \emph{the compiler} in the rest of this document) aims at improving C1X, the Java port of the HotSpot client compiler, both in terms of modularity and peak performance.
+The Graal compiler (simply referred to as \emph{the compiler} in the rest of this document) aims at improving upon C1X, the Java port of the HotSpot client compiler, both in terms of modularity and peak performance.
 The compiler should work with the Maxine VM and the HotSpot VM.
 This document contains information about the proposed design and strategy for developing the compiler.}
 
@@ -82,7 +83,7 @@
 Every edge is classified as either a control flow edge (anti-dependency) or a data flow edge (dependency) and represented as a simple pointer from the source node to the target node.
 It is possible to replace a node with another node without traversing the full graph.
 The graph does not allow data flow edge cycles or control flow edge cycles.
-We achieve this by explicitely modelling loops (see Section~\ref{sec:loops}). 
+We achieve this by explicitly modeling loops (see Section~\ref{sec:loops}). 
 \item[Extensibility:]
 The compiler is extensible by allowing developers to add new compiler phases and new node subclasses without modifying the compiler's sources.
 A node has an abstract way of expressing its semantics and new compiler phases can ask compiler nodes for their properties and capabilities.
@@ -94,7 +95,7 @@
 Compiler phases can choose whether they want to work on the earlier versions of the graph (e.g., escape analysis) or on later versions (e.g., null check elimination).
 \item[Generality:]
 The compiler does not require Java as its input.
-This is achieved by having a graph as the starting point of the compilation and not a Java bytecodes array.
+This is achieved by having a graph as the starting point of the compilation and not a Java bytecode array.
 Building the graph from the Java bytecodes must happen before giving a method to the compiler.
 This enables front-ends for different languages (e.g., Ruby or JavaScript) to provide their own graph.
 Also, there is no dependency on a specific back-end, but the output of the compiler is a graph that can then be converted to a different representation in a final compiler phase.
@@ -102,11 +103,11 @@
 
 \section{Milestones}
 \label{sec:mile}
-The compiler is developed starting from the current C1X source code base.
-This helps us testing the compiler at every intermediate development step on a variety of Java benchmarks.
-We define the following development milestones and when they are considered to be achieved (see Section~\ref{sec:conclusions} for planned dates):
+The compiler is being developed starting from the current C1X source code base.
+This helps us test the compiler at every intermediate development step on a variety of Java benchmarks.
+We define the following development milestones (see Section~\ref{sec:conclusions} for planned dates):
 \begin{description}
-\item[M1:] We have a fully working Graal~VM version with a stripped down C1X compiler that does not perform any optimizations.
+\item[M1:] We have a fully working Graal~VM version with a stripped down C1X compiler that does not perform any optimization.
 \item[M2:] We modified the high-level intermediate representation to be based on the compiler graph data structure.
 \item[M3:] We have reimplemented and reenabled compiler optimizations in the compiler that previously existed in C1X.
 \item[M4:] We have reintegrated the new compiler into the Maxine VM and can use it as a Maxine VM bootstrapping compiler.
@@ -119,11 +120,30 @@
   \item Implementation of a prototype front-end for a different language, e.g., JavaScript.
 \end{itemize}
 
+\section{Project Source Structure}
+In order to support the goal of a modular compiler, the code will be divided into the following source code projects (as subprojects of \textbf{com.oracle.max.graal}).
+
+\begin{description}
+    \item[graph] contains the abstract node implementation, the graph implementation and all the associated tools and auxiliary classes.
+    \item[nodes] contains the implementation of known basic nodes (e.g., phi nodes, control flow nodes, \ldots).
+ 				 Additional node classes should go into separate projects and be specializations of the known basic nodes.
+    \item[java] contains code for building graphs from Java bytecodes and Java-specific nodes.
+    \item[opt] contains optimizations such as global value numbering or conditional constant propagation.
+    \item[compiler] contains the compiler, including:
+        \begin{itemize}
+            \item Scheduling of the compilation phases.
+            \item Implementation of the \emph{compiler interface} (CI).
+            \item Implementation of the final compilation phase that produces the low-level representation.
+            \item Machine code creation, including debug info.
+        \end{itemize}
+\end{description}
+
+
 \section{Graph}
 
 The \emph{intermediate representation}~(IR) of the compiler is designed as a directed graph.
-The graph deals out ids for new nodes and can be queried for the node corresponding to a given id as well as for an unordered list of nodes of the graph.
-Graphs can manage side data structures, which will be automatically invalidated and lazily recomputed whenever the graph changes. Examples for side data structures are dominator trees and temporary schedules. These side data structures will usually be understood by more than one optimization.
+The graph allocates unique ids for new nodes and can be queried for the node corresponding to a given id as well as for an unordered list of nodes of the graph.
+Graphs can manage side data structures (e.g. dominator trees and temporary schedules), which will be automatically invalidated and lazily recomputed whenever the graph changes. These side data structures will usually be understood by more than one optimization.
 
 The nodes of the graph have the following properties:
 \begin{itemize}
@@ -143,8 +163,6 @@
     \end{itemize}
     \item Only inputs and successors can be changed, and changes to them will update the usages and predecessors.
     \item Every node must be able to support cloning and serialization.
-    \item Inlining should always be performed as embedding one graph into another graph.
-    \item Nodes cannot be reassigned to another graph, they are cloned instead.
     \item The edges of a node also define \textit{happens-before} and \textit{happens-after} relationships as shown in Figure~\ref{fig:directions}.
 \end{itemize}
 
@@ -172,30 +190,120 @@
   \label{fig:directions}
 \end{figure}
 
-\subsection{Project Source Structure}
-In order to support the goal of a modular compiler, the code will be divided into the following source code projects (as subprojects of \textbf{com.oracle.graal}).
+\subsection{Inlining}
+Inlining is always performed by embedding one graph into another graph.
+Nodes cannot be reassigned to another graph, they are cloned instead.
+Therefore, inlining is performed by copying and rewiring the nodes of the inlined method into the graph of the outer method.
+While the copying will decrease compilation performance, it enables us to cache the graph for the inlined method, optimize it independently from the outer method, and use the optimized graph for subsequent inlinings.
+We do not expect a significant negative impact on overall compilation performance.
+
+We are able to perform the inlining at any point during the compilation of a method and can therefore selectively expand the inlining if a certain optimization turns out to depend on the inlining of a method.
+An example for this would be when the escape analysis finds out that a certain object only escapes because of one method call and this method call is not inlined, because the penalty was to high.
+In this case, we can chose to nevertheless inline the method in order to increase the chances for finding out that the object does not escape.
+
+\section{Control Flow}
+
+Control flow is managed in way where the predecessor node contains direct pointers to its successor nodes.
+We reserve the term \textit{instruction} for nodes that are embedded in the control flow.
+This is opposite to the approach taken in the server compiler, where control flow and data flow edges point in the same direction.
+The advantage that we see in our approach is that there is no need for projection nodes in case of control flow splits.
+An \texttt{If} instruction can directly point to its true and false successors without any intermediate nodes.
+This makes the graph more compact and simplifies graph traversal.
+
+Listing~\ref{lst:cfg2} shows an example Java program with an if statement where both paths do not contain any instruction with side effects.
+The \texttt{If} instruction can directly point its true and false successors to a \texttt{Merge} instruction.
+A \texttt{Phi} node that selects the appropriate value is appended to the \texttt{Merge} instruction.
+The \texttt{Return} instruction then has a data dependency on the \texttt{Phi} node.
+
+\begin{lstlisting}[label=lst:cfg2, caption=Control flow in the graph., captionpos=b]
+if (condition) { return 0; }
+else { return 1; }
+\end{lstlisting}
 
-\begin{description}
-    \item[graph] contains the abstract node implementation, the graph implementation and all the associated tools and auxiliary classes.
-    \item[nodes] contains the implementation of known basic nodes (e.g., phi nodes, control flow nodes, \ldots).
- 				 Additional node classes should go into separate projects and be specializations of the known basic nodes.
-    \item[java] contains code for building graphs from Java bytecodes and Java-specific nodes.
-    \item[opt] contains optimizations such as global value numbering or conditional constant propagation.
-    \item[compiler] contains the compiler, including:
-        \begin{itemize}
-            \item Scheduling of the compilation phases.
-            \item Implementation of the \emph{compiler interface} (CI).
-            \item Implementation of the final compilation phase that produces the low-level representation.
-            \item Machine code creation, including debug info.
-        \end{itemize}
-\end{description}
+\begin{figure}[h]
+  \centering
+\begin{digraphenv}{scale=0.5}{cfg2}
+\textnode{entry}{Entry}
+\textnode{condition}{condition}
+\textnode{const0}{0}
+\textnode{const1}{1}
+\nodesplit{if}{If}
+\control{entry}{if}
+\controllabel{if:succ1}{merge}
+\controllabel{if:succ2}{merge}
+\data{if}{condition}
+\node{merge}{Merge}
+\node{return}{Return}
+\nodetri{phi}{Phi}
+\datalabel{phi:in1}{merge}
+\datalabel{phi:in2}{const0}
+\datalabel{phi:in3}{const1}
+\data{return}{phi}
+\control{merge}{return}
+\end{digraphenv}
+  \caption{A simple loop with two exits.}
+  \label{fig:exc1}
+\end{figure}
+
+\section{Exceptions}
+\label{sec:Exceptions}
+
+We do not throw runtime exceptions (e.g., \texttt{IndexOutOf\-BoundsException}, \texttt{NullPointerException}, or \texttt{Out\-Of\-MemoryException}), but deoptimize instead.
+This reduces the places in the compiled code where an exact bytecode location and debug information must be known.
+Additionally, this greatly reduces the number of exception handler edges in the compiled code.
+The main advantage of this technique is however, that we are free in moving around bounds checks, memory allocation, memory accesses with implicit null checks, etc.
+
+There are only two kinds of instruction that need explicit exception edges, because they are the only instructions that can throw exceptions in compiled code: \texttt{Throw} instructions and \texttt{Invoke} instructions.
+They are modelled as instructions with an additional control flow continuation that points to an \texttt{ExceptionDispatch} instruction.
+The exception dispatch instruction decides based on the type of the exception object whether the control should flow to the catch handler or to another exception dispatch.
+If there is no catch handler in the currently compiled method, then the control flows into the \texttt{Unwind} instruction that handles the exception by forwarding it to the caller.
+Listing~\ref{lst:exc1} shows an example Java program with nested try blocks and Figure \ref{fig:exc1} shows the corresponding compiler graph.
+
+\begin{lstlisting}[label=lst:exc1, caption=Exception dispatch in the compiler graph., captionpos=b]
+try { m1();
+  try { m2();
+  } catch(ExtendedException e) { ... }
+  m3();
+  throw exception;
+} catch(Exception e) { ... }
+\end{lstlisting}
+
+\begin{figure}[h]
+  \centering
+\begin{digraphenv}{scale=0.5}{exc1}
+\textnode{entry}{Entry}
+\textnode{catch1}{catch1}
+\textnode{catch2}{catch2}
+\nodesplit{m1}{Invoke m1}
+\nodesplit{m2}{Invoke m2}
+\nodesplit{m3}{Invoke m3}
+\nodesplit{dispatch1}{ExceptionDispatch}
+\nodesplit{dispatch2}{ExceptionDispatch}
+\node{throw}{Throw}
+\node{unwind}{Unwind}
+\control{entry}{m1}
+\controllabel{m1:succ1}{m2}
+\controllabel{m1:succ2}{dispatch2}
+\controllabel{m2:succ1}{m3}
+\controllabel{m2:succ2}{dispatch1}
+\controllabel{m3:succ1}{throw}
+\controllabel{m3:succ2}{dispatch2}
+\control{throw}{dispatch2}
+\controllabel{dispatch1:succ2}{catch1}
+\controllabel{dispatch1:succ1}{dispatch2}
+\controllabel{dispatch2:succ2}{catch2}
+\controllabel{dispatch2:succ1}{unwind}
+\end{digraphenv}
+  \caption{A simple loop with two exits.}
+  \label{fig:exc1}
+\end{figure}
 
 \section{Loops}
 \label{sec:loops}
 Loops form a first-class construct in the IR that is expressed by specialized IR nodes during all optimization phases.
 We only compile methods with a control flow where every loop has a single entry point.
-This entry point is a \nodename{LoopBegin} node.
-This node is connected to a \nodename{LoopEnd} node that merges all control flow paths that do not exit the loop.
+This entry point is a \nodename{LoopBegin} instruction.
+This instruction is connected to a \nodename{LoopEnd} instruction that merges all control flow paths that do not exit the loop.
 The edge between the \nodename{LoopBegin} and the \nodename{LoopEnd} is the backedge of the loop.
 It goes from the beginning to the end in order to make the graph acyclic.
 An algorithm that traverses the control flow has to explicitely decide whether it wants to incorporate backedges (i.e., special case of the treatment of \nodename{LoopEnd}) or ignore them.
@@ -224,10 +332,15 @@
 \end{figure}
 
 \subsection{Loop Phis}
-Data flow in loops is modelled with special phi nodes at the beginning and the end of the loop.
-The \nodename{LoopEnd} node merges every value that flows into the next loop iteration in associated \nodename{LoopEndPhi} nodes.
+Data flow in loops is modeled with special phi nodes at the beginning and the end of the loop.
+The \nodename{LoopEnd} instruction merges every value that flows into the next loop iteration in associated \nodename{LoopEndPhi} nodes.
 A corresponding \nodename{LoopBeginPhi} node that is associated with the loop header has a control flow dependency on the \nodename{LoopEndPhi} node.
-Figure \ref{fig:loop2} shows how a simple counting loop is modelled in the graph.
+Listing~\ref{lst:loop} shows a simple counting loop that is used as an example in the rest of this section.
+Figure~\ref{fig:loop2} shows how the loop is modelled immediately after building the graph.
+
+\begin{lstlisting}[label=lst:loop, caption=Loop example that counts from 0 to n-1., captionpos=b]
+for(int i=0; i<n; ++i) { }
+\end{lstlisting}
 
 \begin{figure}[h]
   \centering
@@ -366,23 +479,29 @@
 
 
 \section{Frame States}
-A frame state captures the state of the program in terms of the Java bytecode specification (i.e., the values of the local variables, the operand stack, and the locked monitors).
-Every deoptimization point needs a valid frame state.
-A frame state stays valid as long as the subsequent instructions perform only actions that can safely be reexecuted.
-Thus, frame states need only be generated for the states after bytecodes that cannot be reexecuted:
+A frame state captures the state of the program like it is seen in by an interpreter of the program.
+The frame state contains the information that is local to the current activation and will therefore disappear during SSA-form constructions or other compiler optimizations.
+For Java, the frame state is defined in terms of the Java bytecode specification (i.e., the values of the local variables, the operand stack, and the locked monitors).
+However, a frame state is not a concept specific to Java (e.g., the Crankshaft JavaScript engine uses frame states in their optimizing compiler to model the values of the AST interpreter).
+
+Frame states are necessary to support the deoptimization of the program, which is the precondition for performing aggressive optimizations that use optimistic assumptions.
+Therefore every point in the optimizing compiler that may revert execution back to the interpreter needs a valid frame state.
+However, the point where the interpreter continues execution need not correspond exactly to the execution position of the compiled code, because many Java bytecode instructions can be safely reexecuted.
+Thus, frame states need only be generated for the states after instructions that cannot be reexecuted, because they modify the state of the program.
+Examples for such instructions are:
 
 \begin{itemize}
-    \item Array stores: {\tt IASTORE, LASTORE, FASTORE, \\DASTORE, AASTORE, BASTORE, CASTORE, SASTORE}
-    \item Field stores: {\tt PUTSTATIC, PUTFIELD}
-    \item Method calls: {\tt INVOKEVIRTUAL, INVOKESPECIAL, \\INVOKESTATIC, INVOKEINTERFACE}
-    \item Synchronization: {\tt MONITORENTER, MONITOREXIT}
+    \item Array stores (in Java bytecodes {\tt IASTORE, LASTORE, FASTORE, \\DASTORE, AASTORE, BASTORE, CASTORE, SASTORE})
+    \item Field stores (in Java bytecodes {\tt PUTSTATIC, PUTFIELD})
+    \item Method calls (in Java bytecodes {\tt INVOKEVIRTUAL, INVOKESPECIAL, \\INVOKESTATIC, INVOKEINTERFACE})
+    \item Synchronization (in Java bytecodes {\tt MONITORENTER, MONITOREXIT})
 \end{itemize}
 
-Within the graph a frame state is represented as a node that is attached to the node that caused it to be generated using a control dependency (see Figure~\ref{fig:fs1}).
+Within the graph a frame state is represented as a node that is attached to the instruction that caused it to be generated using a control dependency (see Figure~\ref{fig:fs1}).
 Frame states also have data dependencies on the contents of the state: the local variables and the expression stack.
 
 The frame state at the method beginning does not have to be explicitely in the graph, because it can always be reconstructed at a later stage.
-We save the frame state at control flow merges if there is at least one frame state on any control flow path after the immediate dominator.
+We save the frame state at control flow merges if there is at least one frame state on any control flow path between a node and its immediate dominator.
 
 
 \begin{figure}[h]
@@ -406,113 +525,312 @@
 \end{figure}
 
 
+A deoptimization node needs a valid frame state that specifies the location and state where the interpreter should continue.
+The algorithm for constructing frame states makes sure that every possible location in the graph has a well-defined frame state that can be used by a deoptimization instruction.
+Therefore, there are no direct links between the deoptimization instruction and its frame state thus allowing the deoptimization instructions to move freely around.
+
+\subsection{Partial Escape Analysis}
+
+A partial escape analysis can help to further reduce the number of frame states.
+A field or array store does not create a new frame state, when the object that is modified did not have a chance to escape between its creation and the store.
+
+Listing~\ref{lst:escape1} shows an example of a method that creates two \texttt{Point} objects, connects them, and returns them.
+The object allocation of the first \texttt{Point} object does not need a frame state.
+We can always reexecute the \texttt{NEW} bytecode again in the interpreter.
+The \texttt{Point} object allocated by the compiler will then simply disappear after the next garbage collection.
+The following field store is a thread-local memory store, because the \texttt{Point} object did not have any chance to escape.
+Same applies to the assignment of the \texttt{next} field and the third field assignment.
+Therefore, the whole method \texttt{getPoint} does not need an explicit frame state, because at any time during execution of this method, we can deoptimize and continue execution in the interpreter at the first bytecode of the method.
+
+\begin{lstlisting}[label=lst:escape1, caption=Example method that needs no frame state., captionpos=b]
+void getPoint() {
+  Point p = new Point();
+  p.x = 1;
+  p.next = new Point();
+  p.next.x = 2;
+  return p;
+}
+\end{lstlisting}
+
+The reduction of frame states makes it easier for the compiler to perform memory optimizations like memory access coalescing.
+We believe that this reduction on frame states is the key to effective vectorization and other compiler optimizations where compilers of compilers of unmanaged languages have advantages.
+
 \subsection{Guards}
-A guard node is a node that deoptimizes based on a conditional expression.
-Guard nodes are not attached to a certain frame state node, they can move around freely and will always use the correct frame state when the nodes are scheduled (i.e., the last emitted frame state).
-The node that is guarded by the deoptimization has a data dependency on the guard, and the guard in turn has a data dependency on the condition and on the most distant node that is postdominated by the guarded node.
+A guard is a node that deoptimizes based on a conditional expression.
+Guards are not attached to a certain frame state, they can move around freely and will always use the correct frame state when the nodes are scheduled (i.e., the last emitted frame state).
+The node that is guarded by the deoptimization has a data dependency on the guard and the guard in turn has a data dependency on the condition.
+A guard must not be moved above any \texttt{If} nodes.
+Therefore, we use \texttt{Anchor} instructions after a control flow split and a data dependency from the guard to this anchor.
+The anchor is the most distant instruction that is postdominated by the guarded instruction and the guard can be scheduled anywhere between those two nodes.
+This ensures maximum flexibility for the guard instruction and guarantees that we only deoptimize if the control flow would have reached the guarded instruction (without taking exceptions into account).
+
+To illustrate the strengths of this approach, we show the graph for the Java code snippet shown in \ref{lst:guard1}.
+The example looks artificial, but in case of method inlining, this is a pattern that is not unlikely to be present in a normal Java program.
+Figure \ref{fig:guard0} shows the compiler graph for the example method after graph building.
+The field stores are both represented by a single instruction and the null check that is implicitely incorporated in the field store.
+
+\begin{lstlisting}[label=lst:guard1, caption=Example method that demonstrates the strengths of modelling the guards explicitely., captionpos=b]
+void init(Point p) {
+  if (p != null) {
+    p.x = 0;
+  }
+  p.y = 0;
+}
+\end{lstlisting}
 
-In the example of Figure~\ref{fig:guard1}, the second load is guarded by a guard, because its receiver might be null (the receiver of the first load is assumed to be non-null).
-The guard is anchored to the control split, because as soon as this node is executed, the second load must be executed as well.
-In the final schedule, the guard can be placed before or after the first load.
+\begin{figure}[h]
+  \centering
+\begin{digraphenv}{scale=0.5}{guard0}
+	\textnode{entry}{Entry}
+    \nodesplit{if}{If}
+    \node{merge}{Merge}
+    \node{return}{Return}
+    \node{cmpnull}{NonNull}
+    \textnode{p}{p}
+	\textnode{const0}{0}
+    \nodebisplit{store1}{FieldStore x}
+    \nodebisplit{store2}{FieldStore y}
+    \nodeframestate{fs1}{FrameState}
+    \nodeframestate{fs2}{FrameState}
+    \datalabel{store1:in1}{p}
+    \datalabel{store2:in1}{p}
+    \datalabel{store1:in2}{const0}
+    \datalabel{store2:in2}{const0}
+    \control{entry}{if}
+    \data{if}{cmpnull}
+    \controllabel{if:succ1}{merge}
+    \controllabel{if:succ2}{store1}
+    \controllabel{store1:succ1}{merge}
+    \controllabel{store1:succ2}{fs1}
+    \control{merge}{store2}
+    \controllabel{store2:succ1}{return}
+    \controllabel{store2:succ2}{fs2}
+    \data{cmpnull}{p}
+\end{digraphenv}
+  \caption{Initial graph with the two field stores.}
+  \label{fig:guard0}
+\end{figure}
+
+Figure~\ref{fig:guard1} shows the example graph at a later compilation phase when the field store instructions are lowered to memory store instructions and explicitely modelled null check guards.
+The guards are attached to anchor instructions that delimit their possible schedule.
+The first guard must not be moved outside the \texttt{if} block; the second guard may be moved before the \texttt{If} instruction, because at this point it is already guaranteed that the second store is executed.
 
 \begin{figure}[h]
   \centering
 \begin{digraphenv}{scale=0.5}{guard1}
+	\textnode{entry}{Entry}
+    \node{anchor1}{Anchor}
+    \node{anchor2}{Anchor}
     \nodesplit{if}{If}
-    nop [shape=plaintext, label="..."]
-    \controllabel{if:succ1}{nop}
-    %
-    \node{split2}{Anchor}
-    \controllabel{if:succ2}{split2}
-    \nodebi{load1}{MemLoad}
-    \control{split2}{load1}
-    \nodebi{load2}{MemLoad}
-    \control{load1}{load2}
-    \control{load2}{merge}
     \node{merge}{Merge}
-    \control{nop}{merge}
-    %
-    \nodeconst{o1}{obj1}
-    \nodeconst{o2}{obj2}
-    \datalabel{load1:in2}{o1}
-    \datalabel{load2:in2}{o2}
-    \nodeguard{guard}{Guard}
-    \node{cmpnull}{IsNull}
-    \data{cmpnull}{o2}
-    \datalabel{guard:in2}{cmpnull}
-    \datalabel{load2:in1}{guard}    
-    \datalabel{guard:in1}{split2}
+    \node{return}{Return}
+    \node{cmpnull}{NonNull}
+    \textnode{p}{p}
+	\textnode{const0}{0}
+    \nodeguard{guard1}{Guard}
+    \nodeguard{guard2}{Guard}
+    \nodetrisplit{store1}{MemStore 16 (int)}
+    \nodetrisplit{store2}{MemStore 20 (int)}
+    \nodeframestate{fs1}{FrameState}
+    \nodeframestate{fs2}{FrameState}
+    \data{store1:in1}{p}
+    \data{store2:in1}{p}
+    \data{store1:in2}{const0}
+    \data{store2:in2}{const0}
+    \data{store1:in3}{guard1}
+    \data{store2:in3}{guard2}
+    \data{guard1:in1}{anchor2}
+    \data{guard2:in1}{anchor1}
+    \data{guard1:in2}{cmpnull}
+    \data{guard2:in2}{cmpnull}
+    \control{entry}{anchor1}
+    \control{anchor1}{if}
+    \data{if}{cmpnull}
+    \controllabel{if:succ1}{merge}
+    \controllabel{if:succ2}{anchor2}
+    \control{anchor2}{store1}
+    \controllabel{store1:succ1}{merge}
+    \controllabel{store1:succ2}{fs1}
+    \control{merge}{store2}
+    \controllabel{store2:succ1}{return}
+    \controllabel{store2:succ2}{fs2}
+    \data{cmpnull}{p}
 \end{digraphenv}
   \caption{A load guarded by a null check guard.}
   \label{fig:guard1}
 \end{figure}
 
-A guard can be used to remove branches that have a very low execution frequency and replace them with a conditional jump to deoptimization.
+The first guard can be easily removed, because it is guarded by an \texttt{If} instruction that checks the same condition.
+Therefore we can remove the guard and the anchor from the graph and this gives us the graph shown in Figure \ref{fig:guard2}.
 
-In the example of Figure~\ref{fig:guard2}, an \texttt{If} node was replaced by an anchor and a guard.
-The anchor takes the place of the \texttt{If} node in the control flow, and is connected to the guard node.
-The guard is now anchored to the most distant node of which the \texttt{If} node was a postdominator.
+There is another optimization for guard instructions: If two guards that are anchored to the true and false branch of the same \texttt{If} instruction have the same condition, they can be merged, so that the resulting guard is anchored at the most distant node of which the \texttt{If} instruction is a postdominator.
+
 
 \begin{figure}[h]
   \centering
 \begin{digraphenv}{scale=0.5}{guard2}
-    start [shape=plaintext, label="..."]
-    start2 [shape=plaintext, label=""]
-    start3 [shape=plaintext, label=""]
-    \control{start}{guard}
-    \node{anchor}{Anchor}
-    \nodebi{load1}{MemLoad}
-    \control{anchor}{load1}
-    \control{load1}{nop}
-    nop [shape=plaintext, label="..."]
-    %
-    \nodeguard{guard}{Guard}
-    \datalabel{guard:in1}{start2}
-    \datalabel{guard:in2}{start3}
-    \data{anchor}{guard}    
+	\textnode{entry}{Entry}
+    \node{anchor1}{Anchor}
+    \nodesplit{if}{If}
+    \node{merge}{Merge}
+    \node{return}{Return}
+    \node{cmpnull}{NonNull}
+    \textnode{p}{p}
+	\textnode{const0}{0}
+    \nodeguard{guard2}{Guard}
+    \nodetrisplit{store1}{MemStore 16 (int)}
+    \nodetrisplit{store2}{MemStore 20 (int)}
+    \nodeframestate{fs1}{FrameState}
+    \nodeframestate{fs2}{FrameState}
+    \data{store1:in1}{p}
+    \data{store2:in1}{p}
+    \data{store1:in2}{const0}
+    \data{store2:in2}{const0}
+    \data{store2:in3}{guard2}
+    \data{guard2:in1}{anchor1}
+    \data{guard2:in2}{cmpnull}
+    \control{entry}{anchor1}
+    \control{anchor1}{if}
+    \data{if}{cmpnull}
+    \controllabel{if:succ1}{merge}
+    \controllabel{if:succ2}{store1}
+    \controllabel{store1:succ1}{merge}
+    \controllabel{store1:succ2}{fs1}
+    \control{merge}{store2}
+    \controllabel{store2:succ1}{return}
+    \controllabel{store2:succ2}{fs2}
+    \data{cmpnull}{p}  
 \end{digraphenv}
-  \caption{A guard that is fixed to the control flow using an anchor instruction.}
+  \caption{After removing redundant guards.}
   \label{fig:guard2}
 \end{figure}
 
-At some point during the compilation, guard nodes need to be fixed, which means that appropriate data and control dependencies will be inserted so that they cannot move outside the scope of the associated frame state.
-This will generate deoptimization-free zones that can be targeted by the most aggressive optimizations.
-A simple algorithm for this removal of frame states would be to move all guards as far upwards as possible.
-Multiple guards with the same condition and anchor can be merged (see Figure~\ref{fig:guard3}).
+The remaining guard can now be moved above the \texttt{If} condition and be used to eliminate the need for the \texttt{If} node.
+From this point on, the guard can however no longer be moved below the first memory store.
+We use a control dependency from the guard to the field store to express this condition.
+The link between the second store and the guard and the control flow merge instruction is no longer necessary.
 
 \begin{figure}[h]
   \centering
 \begin{digraphenv}{scale=0.5}{guard3}
-    \nodesplit{if}{If}
-    nop [shape=plaintext, label="..."]
-    \controllabel{if:succ1}{nop}
-    %
-    \node{split2}{Anchor}
-    \controllabel{if:succ2}{split2}
-    \nodebi{load1}{MemLoad}
-    \control{split2}{load1}
-    \nodebi{load2}{MemLoad}
-    \control{load1}{load2}
-    \control{load2}{merge}
-    \node{merge}{Merge}
-    \control{nop}{merge}
-    %
-    \nodeconst{o}{obj}
-    \datalabel{load1:in2}{o}
-    \datalabel{load2:in2}{o}
-    \nodeguard{guard}{Guard}
-    \node{cmpnull}{IsNull}
-    \data{cmpnull}{o}
-    \datalabel{guard:in2}{cmpnull}
-    \datalabel{load2:in1}{guard}    
-    \datalabel{load1:in1}{guard}    
-    \datalabel{guard:in1}{split2}
+	\textnode{entry}{Entry}
+    \node{anchor1}{Anchor}
+    \node{return}{Return}
+    \node{cmpnull}{NonNull}
+    \textnode{p}{p}
+	\textnode{const0}{0}
+    \nodeguard{guard2}{Guard}
+    \nodetrisplit{store1}{MemStore 16 (int)}
+    \nodetrisplit{store2}{MemStore 20 (int)}
+    \nodeframestate{fs1}{FrameState}
+    \nodeframestate{fs2}{FrameState}
+    \data{store1:in1}{p}
+    \data{store2:in1}{p}
+    \data{store1:in2}{const0}
+    \data{store2:in2}{const0}
+    \data{store2:in3}{guard2}
+    \data{guard2:in1}{anchor1}
+    \data{guard2:in2}{cmpnull}
+    \control{guard2}{store1}
+    \control{entry}{anchor1}
+    \control{anchor1}{store1}
+    \controllabel{store1:succ2}{fs1}
+    \control{store1}{store2}
+    \controllabel{store2:succ1}{return}
+    \controllabel{store2:succ2}{fs2}
+    \data{cmpnull}{p}  
 \end{digraphenv}
-  \caption{Two loads using the same guard.}
+  \caption{After eliminating an if with a guard.}
   \label{fig:guard3}
 \end{figure}
 
-Also, if two guards that are anchored to the true and false branch of the same \texttt{If} node have the same condition, they can be merged, so that the resulting guard is anchored at the most distant node of which the \texttt{If} node is a postdominator.
+At some point during the compilation, guards need to be fixed, which means that appropriate data and control dependencies will be inserted so that they cannot move outside the scope of the associated frame state.
+This will generate deoptimization-free zones that can be targeted by the most aggressive optimizations.
+A simple algorithm for this removal of frame states would be to move all guards as far upwards as possible and then the guards are fixed using anchor nodes.
+In our example, the guard is already fixed, so there is no deoptimization point that uses any of the memory store frame states.
+Therefore we can delete the frame states from the graph (see Figure \ref{fig:guard4}).
+
+\begin{figure}[h]
+  \centering
+\begin{digraphenv}{scale=0.5}{guard4}
+	\textnode{entry}{Entry}
+    \node{anchor1}{Anchor}
+    \node{return}{Return}
+    \node{cmpnull}{NonNull}
+    \textnode{p}{p}
+	\textnode{const0}{0}
+    \nodeguard{guard2}{Guard}
+    \nodetrisplit{store1}{MemStore 16 (int)}
+    \nodetrisplit{store2}{MemStore 20 (int)}
+    \data{store1:in1}{p}
+    \data{store2:in1}{p}
+    \data{store1:in2}{const0}
+    \data{store2:in2}{const0}
+    \data{store2:in3}{guard2}
+    \data{guard2:in1}{anchor1}
+    \data{guard2:in2}{cmpnull}
+    \control{guard2}{store1}
+    \control{entry}{anchor1}
+    \control{anchor1}{store1}
+    \control{store1}{store2}
+    \controllabel{store2:succ1}{return}
+    \data{cmpnull}{p}  
+\end{digraphenv}
+  \caption{After removing the frame states.}
+  \label{fig:guard4}
+\end{figure}
+
+Now we can use memory coalescing to combine the two stores without frame state to adjacent locations in the same object.
+This is only possible if the first store does not have a frame state.
+Figure \ref{fig:guard5} shows the resulting graph.
+
+
+\begin{figure}[h]
+  \centering
+\begin{digraphenv}{scale=0.5}{guard5}
+	\textnode{entry}{Entry}
+    \node{anchor1}{Anchor}
+    \node{return}{Return}
+    \node{cmpnull}{NonNull}
+    \textnode{p}{p}
+	\textnode{const0}{0}
+    \nodeguard{guard2}{Guard}
+    \nodetrisplit{store1}{MemStore 16 (long)}
+    \data{store1:in1}{p}
+    \data{store1:in2}{const0}
+    \data{guard2:in1}{anchor1}
+    \data{guard2:in2}{cmpnull}
+    \control{guard2}{store1}
+    \control{entry}{anchor1}
+    \control{anchor1}{store1}
+    \controllabel{store1:succ1}{return}
+    \data{cmpnull}{p}  
+\end{digraphenv}
+  \caption{After coalescing the two memory stores.}
+  \label{fig:guard5}
+\end{figure}
+
+A memory store that immediately follows a null check guard instruction on the same object, can be combined into a store with an implicit null check (that deoptimizes instead of throwing the exception).
+Therefore, we can remove the guard again and also the anchor is no longer necessary.
+Figure~\ref{fig:guard6} shows now that fully optimized graph that is generated for Listing~\ref{lst:guard1}.
+
+\begin{figure}[h]
+  \centering
+\begin{digraphenv}{scale=0.5}{guard6}
+	\textnode{entry}{Entry}
+    \node{return}{Return}
+    \textnode{p}{p}
+	\textnode{const0}{0}
+    \nodetrisplit{store1}{DeoptimizingMemStore 16 (long)}
+    \data{store1:in1}{p}
+    \data{store1:in2}{const0}
+    \control{entry}{store1}
+    \controllabel{store1:succ1}{return}
+\end{digraphenv}
+  \caption{Fully optimized method.}
+  \label{fig:guard6}
+\end{figure}
+
 
 \section{Conclusions}
 \label{sec:conclusions}
@@ -523,6 +841,6 @@
 \item[M3:] August 15th, 2011
 \item[M4:] September 30th, 2011
 \end{description}
-After we reached M4, we want to create a new project road map that further improves the Graal compiler with respect to its two main goals: Modularity and peak performance.
+After we reach M4, we want to create a new project road map that further improves the Graal compiler with respect to its two main goals: Modularity and peak performance.
 
 \end{document}
--- a/doc/design/graphdrawing.tex	Wed May 18 18:09:20 2011 +0200
+++ b/doc/design/graphdrawing.tex	Wed May 18 18:40:58 2011 +0200
@@ -1,7 +1,7 @@
 
 % graph drawing
+\newwrite\dotfile 
 \newcommand{\digraph}[3][scale=1]{ 
-  \newwrite\dotfile 
   \immediate\openout\dotfile=dot_temp_#2.dot 
   \immediate\write\dotfile{digraph #2 { margin=0; pad=0; concentrate=false; \string#3}} 
   \immediate\closeout\dotfile
@@ -21,7 +21,7 @@
   } 
 }
 
-\NewEnviron{digraphenv}[2]{\digraph[#1]{#2}{ nodesep="0.1"; ranksep="0.18 equally"; \BODY }}
+\NewEnviron{digraphenv}[2]{\digraph[#1]{#2}{ nodesep="0.1"; ranksep="0.08 equally"; \BODY }}
 
 \newcommand{\control}[2]{#1:successors:s -> #2:predecessors:n [color=red];}
 \newcommand{\controllabel}[2]{#1:s -> #2:predecessors:n [color=red];}
@@ -53,6 +53,7 @@
 \newcommand{\nodequadsplit}[2]{\genericnodestart{#1} \portinput{in1} \portinput{in2} \portinput{in3} \portinput{in4} \genericnodelabel{#2}{white} \portsuccessor{succ1} \portsuccessor{succ2} \portempty \portempty \genericnodeend }
 \newcommand{\nodetrisplit}[2]{\genericnodestart{#1} \portinput{in1} \portinput{in2} \portinput{in3} \genericnodelabel{#2}{white} \portsuccessor{succ1} \portsuccessor{succ2} \portempty \genericnodeend }
 \newcommand{\nodesplittri}[2]{\genericnodestart{#1} \portempty \portinput{inputs} \genericnodelabel{#2}{white} \portsuccessor{succ1} \portsuccessor{succ2} \portsuccessor{succ3} \genericnodeend }
+\newcommand{\nodebisplit}[2]{\genericnodestart{#1} \portinput{in1} \portinput{in2} \genericnodelabel{#2}{white} \portsuccessor{succ1} \portsuccessor{succ2} \portempty \genericnodeend }
 
 \newcommand{\nodeguard}[2]{\cnodebi{#1}{#2}{rosybrown1}}
 
--- a/graal/GraalCompiler/.classpath	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/.classpath	Wed May 18 18:40:58 2011 +0200
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry combineaccessrules="false" exported="true" kind="src" path="/CRI"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/GraalGraph"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/GraalGraphviz"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/com.oracle.max.asm"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/GraalGraph"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/GraalGraphviz"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/com.oracle.max.asm"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/com.oracle.max.cri"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Wed May 18 18:40:58 2011 +0200
@@ -246,6 +246,7 @@
             initFrameMap(hir.maxLocks());
 
             lirGenerator = compiler.backend.newLIRGenerator(this);
+
             for (BlockBegin begin : hir.linearScanOrder()) {
                 lirGenerator.doBlock(begin);
             }
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XCompiler.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XCompiler.java	Wed May 18 18:40:58 2011 +0200
@@ -131,6 +131,15 @@
         if (C1XOptions.PrintDOTGraphToPdf) {
             addCompilationObserver(new GraphvizPrinterObserver(true));
         }
+        if (C1XOptions.PrintIdealGraphLevel != 0) {
+            CompilationObserver observer;
+            if (C1XOptions.PrintIdealGraphFile) {
+                observer = new IdealGraphPrinterObserver();
+            } else {
+                observer = new IdealGraphPrinterObserver(C1XOptions.PrintIdealGraphAddress, C1XOptions.PrintIdealGraphPort);
+            }
+            addCompilationObserver(observer);
+        }
     }
 
     public GlobalStub lookupGlobalStub(GlobalStub.Id id) {
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java	Wed May 18 18:40:58 2011 +0200
@@ -69,6 +69,10 @@
     public static boolean PrintCFGToFile                     = ____;
     public static boolean PrintDOTGraphToFile                = ____;
     public static boolean PrintDOTGraphToPdf                 = ____;
+    public static int     PrintIdealGraphLevel               = 0;
+    public static boolean PrintIdealGraphFile                = ____;
+    public static String  PrintIdealGraphAddress             = "127.0.0.1";
+    public static int     PrintIdealGraphPort                = 4444;
     public static boolean OmitDOTFrameStates                 = true;
     public static boolean PrintMetrics                       = ____;
     public static boolean PrintTimers                        = ____;
@@ -87,10 +91,6 @@
     public static boolean PrintAssumptions                   = ____;
     public static boolean QuietBailout                       = ____;
 
-    // all optimization settings
-    public static boolean OptBlockSkipping;
-    public static boolean OptControlFlow;
-
     // optimistic optimization settings
     public static boolean UseAssumptions                = true;
 
@@ -152,7 +152,6 @@
 
         // Level 1 optimizations
         PhiLoopStores                   = l;
-        OptControlFlow                  = l;
 
         // Level 2 optimizations
         OptInline                       = ll;
@@ -160,6 +159,5 @@
         // Level 3 optimizations
         UseStackMapTableLiveness        = lll;
         UseAssumptions                  = lll;
-        OptBlockSkipping                = lll;
     }
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/ControlFlowOptimizer.java	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,271 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.sun.c1x.alloc;
-
-import java.util.*;
-
-import com.sun.c1x.*;
-import com.sun.c1x.graph.*;
-import com.sun.c1x.ir.*;
-import com.sun.c1x.lir.*;
-import com.sun.c1x.util.*;
-import com.sun.cri.ci.*;
-
-/**
- * This class performs basic optimizations on the control flow graph after LIR generation.
- *
- * @author Thomas Wuerthinger
- */
-final class ControlFlowOptimizer {
-
-    /**
-     * Performs control flow optimizations on the given IR graph.
-     * @param ir the IR graph that should be optimized
-     */
-    public static void optimize(IR ir) {
-        ControlFlowOptimizer optimizer = new ControlFlowOptimizer(ir);
-        List<BlockBegin> code = ir.linearScanOrder();
-        optimizer.reorderShortLoops(code);
-        optimizer.deleteEmptyBlocks(code);
-        optimizer.deleteUnnecessaryJumps(code);
-        optimizer.deleteJumpsToReturn(code);
-    }
-
-    private final IR ir;
-
-    private ControlFlowOptimizer(IR ir) {
-        this.ir = ir;
-    }
-
-    private void reorderShortLoop(List<BlockBegin> code, BlockBegin headerBlock, int headerIdx) {
-        int i = headerIdx + 1;
-        int maxEnd = Math.min(headerIdx + C1XOptions.MaximumShortLoopSize, code.size());
-        while (i < maxEnd && code.get(i).loopDepth() >= headerBlock.loopDepth()) {
-            i++;
-        }
-
-        if (i == code.size() || code.get(i).loopDepth() < headerBlock.loopDepth()) {
-            int endIdx = i - 1;
-            BlockBegin endBlock = code.get(endIdx);
-
-            if (endBlock.numberOfSux() == 1 && endBlock.suxAt(0) == headerBlock) {
-                // short loop from headerIdx to endIdx found . reorder blocks such that
-                // the headerBlock is the last block instead of the first block of the loop
-
-                for (int j = headerIdx; j < endIdx; j++) {
-                    code.set(j, code.get(j + 1));
-                }
-                code.set(endIdx, headerBlock);
-
-                // correct the flags so that any loop alignment occurs in the right place.
-                assert code.get(endIdx).checkBlockFlag(BlockBegin.BlockFlag.BackwardBranchTarget) : "must be backward branch target";
-                code.get(endIdx).clearBlockFlag(BlockBegin.BlockFlag.BackwardBranchTarget);
-                code.get(headerIdx).setBlockFlag(BlockBegin.BlockFlag.BackwardBranchTarget);
-            }
-        }
-    }
-
-    private void reorderShortLoops(List<BlockBegin> code) {
-        for (int i = code.size() - 1; i >= 0; i--) {
-            BlockBegin block = code.get(i);
-
-            if (block.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader)) {
-                reorderShortLoop(code, block, i);
-            }
-        }
-
-        assert verify(code);
-    }
-
-    // only blocks with exactly one successor can be deleted. Such blocks
-    // must always end with an unconditional branch to this successor
-    private boolean canDeleteBlock(BlockBegin block) {
-        if (block.numberOfSux() != 1 ||
-            block == ir.startBlock ||
-            block.suxAt(0) == block) {
-            return false;
-        }
-
-        List<LIRInstruction> instructions = block.lir().instructionsList();
-
-        assert instructions.size() >= 2 : "block must have label and branch";
-        assert instructions.get(0).code == LIROpcode.Label : "first instruction must always be a label";
-        assert instructions.get(instructions.size() - 1) instanceof LIRBranch : "last instruction must always be a branch";
-        assert ((LIRBranch) instructions.get(instructions.size() - 1)).cond() == Condition.TRUE : "branch must be unconditional";
-        assert ((LIRBranch) instructions.get(instructions.size() - 1)).block() == block.suxAt(0) : "branch target must be the successor";
-
-        // block must have exactly one successor
-
-        return instructions.size() == 2 && instructions.get(instructions.size() - 1).info == null;
-    }
-
-    private void deleteEmptyBlocks(List<BlockBegin> code) {
-        int oldPos = 0;
-        int newPos = 0;
-        int numBlocks = code.size();
-
-        while (oldPos < numBlocks) {
-            BlockBegin block = code.get(oldPos);
-
-            if (canDeleteBlock(block)) {
-                BlockBegin newTarget = block.suxAt(0);
-
-                // propagate backward branch target flag for correct code alignment
-                if (block.checkBlockFlag(BlockBegin.BlockFlag.BackwardBranchTarget)) {
-                    newTarget.setBlockFlag(BlockBegin.BlockFlag.BackwardBranchTarget);
-                }
-
-                // update the block references in any branching LIR instructions
-                for (Instruction pred : block.blockPredecessors()) {
-                    for (LIRInstruction instr : pred.block().lir().instructionsList()) {
-                        if (instr instanceof LIRBranch) {
-                            ((LIRBranch) instr).substitute(block, newTarget);
-                        } else if (instr instanceof LIRTableSwitch) {
-                            ((LIRTableSwitch) instr).substitute(block, newTarget);
-                        }
-                    }
-                }
-
-                // adjust successor and predecessor lists
-                ir.replaceBlock(block, newTarget);
-                C1XMetrics.BlocksDeleted++;
-            } else {
-                // adjust position of this block in the block list if blocks before
-                // have been deleted
-                if (newPos != oldPos) {
-                    code.set(newPos, code.get(oldPos));
-                }
-                newPos++;
-            }
-            oldPos++;
-        }
-        Util.truncate(code, newPos);
-
-        assert verify(code);
-    }
-
-    private void deleteUnnecessaryJumps(List<BlockBegin> code) {
-        // skip the last block because there a branch is always necessary
-        for (int i = code.size() - 2; i >= 0; i--) {
-            BlockBegin block = code.get(i);
-            List<LIRInstruction> instructions = block.lir().instructionsList();
-
-            LIRInstruction lastOp = instructions.get(instructions.size() - 1);
-            if (lastOp.code == LIROpcode.Branch) {
-                assert lastOp instanceof LIRBranch : "branch must be of type LIRBranch";
-                LIRBranch lastBranch = (LIRBranch) lastOp;
-
-                assert lastBranch.block() != null : "last branch must always have a block as target";
-                assert lastBranch.label() == lastBranch.block().label() : "must be equal";
-
-                if (lastBranch.info == null) {
-                    if (lastBranch.block() == code.get(i + 1)) {
-                        // delete last branch instruction
-                        Util.truncate(instructions, instructions.size() - 1);
-
-                    } else {
-                        LIRInstruction prevOp = instructions.get(instructions.size() - 2);
-                        if (prevOp.code == LIROpcode.Branch || prevOp.code == LIROpcode.CondFloatBranch) {
-                            assert prevOp instanceof LIRBranch : "branch must be of type LIRBranch";
-                            LIRBranch prevBranch = (LIRBranch) prevOp;
-
-                            if (prevBranch.block() == code.get(i + 1) && prevBranch.info == null) {
-                                // eliminate a conditional branch to the immediate successor
-                                prevBranch.changeBlock(lastBranch.block());
-                                prevBranch.negateCondition();
-                                Util.truncate(instructions, instructions.size() - 1);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        assert verify(code);
-    }
-
-    private void deleteJumpsToReturn(List<BlockBegin> code) {
-        for (int i = code.size() - 1; i >= 0; i--) {
-            BlockBegin block = code.get(i);
-            List<LIRInstruction> curInstructions = block.lir().instructionsList();
-            LIRInstruction curLastOp = curInstructions.get(curInstructions.size() - 1);
-
-            assert curInstructions.get(0).code == LIROpcode.Label : "first instruction must always be a label";
-            if (curInstructions.size() == 2 && curLastOp.code == LIROpcode.Return) {
-                // the block contains only a label and a return
-                // if a predecessor ends with an unconditional jump to this block, then the jump
-                // can be replaced with a return instruction
-                //
-                // Note: the original block with only a return statement cannot be deleted completely
-                // because the predecessors might have other (conditional) jumps to this block.
-                // this may lead to unnecesary return instructions in the final code
-
-                assert curLastOp.info == null : "return instructions do not have debug information";
-
-                assert curLastOp instanceof LIROp1 : "return must be LIROp1";
-                CiValue returnOpr = ((LIROp1) curLastOp).operand();
-
-                for (int j = block.numberOfPreds() - 1; j >= 0; j--) {
-                    BlockBegin pred = block.predAt(j).block();
-                    List<LIRInstruction> predInstructions = pred.lir().instructionsList();
-                    LIRInstruction predLastOp = predInstructions.get(predInstructions.size() - 1);
-
-                    if (predLastOp.code == LIROpcode.Branch) {
-                        assert predLastOp instanceof LIRBranch : "branch must be LIRBranch";
-                        LIRBranch predLastBranch = (LIRBranch) predLastOp;
-
-                        if (predLastBranch.block() == block && predLastBranch.cond() == Condition.TRUE && predLastBranch.info == null) {
-                            // replace the jump to a return with a direct return
-                            // Note: currently the edge between the blocks is not deleted
-                            predInstructions.set(predInstructions.size() - 1, new LIROp1(LIROpcode.Return, returnOpr));
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private boolean verify(List<BlockBegin> code) {
-        for (BlockBegin block : code) {
-            List<LIRInstruction> instructions = block.lir().instructionsList();
-
-            for (LIRInstruction instr : instructions) {
-                if (instr instanceof LIRBranch) {
-                    LIRBranch opBranch = (LIRBranch) instr;
-                    assert opBranch.block() == null || code.contains(opBranch.block()) : "missing successor branch from: " + block + " to: " + opBranch.block();
-                    assert opBranch.unorderedBlock() == null || code.contains(opBranch.unorderedBlock()) : "missing successor branch from: " + block + " to: " + opBranch.unorderedBlock();
-                }
-            }
-
-            for (BlockBegin sux : block.end().blockSuccessors()) {
-                assert code.contains(sux) : "missing successor from: " + block + "to: " + sux;
-            }
-
-            for (Instruction pred : block.blockPredecessors()) {
-                assert code.contains(pred.block()) : "missing predecessor from: " + block + "to: " + pred.block();
-            }
-        }
-
-        return true;
-    }
-}
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Wed May 18 18:40:58 2011 +0200
@@ -563,7 +563,7 @@
 
         for (int i = 0; i < numBlocks; i++) {
             BlockBegin block = blockAt(i);
-            block.setFirstLirInstructionId(opId);
+            block.lirBlock.setFirstLirInstructionId(opId);
             List<LIRInstruction> instructions = block.lir().instructionsList();
 
             int numInst = instructions.size();
@@ -578,7 +578,7 @@
                 index++;
                 opId += 2; // numbering of lirOps by two
             }
-            block.setLastLirInstructionId(opId - 2);
+            block.lirBlock.setLastLirInstructionId((opId - 2));
         }
         assert index == numInstructions : "must match";
         assert (index << 1) == opId : "must match: " + (index << 1);
@@ -1159,8 +1159,8 @@
         for (int i = blockCount() - 1; i >= 0; i--) {
             BlockBegin block = blockAt(i);
             List<LIRInstruction> instructions = block.lir().instructionsList();
-            final int blockFrom = block.firstLirInstructionId();
-            int blockTo = block.lastLirInstructionId();
+            final int blockFrom = block.lirBlock.firstLirInstructionId();
+            int blockTo = block.lirBlock.lastLirInstructionId();
 
             assert blockFrom == instructions.get(0).id;
             assert blockTo == instructions.get(instructions.size() - 1).id;
@@ -1512,14 +1512,14 @@
         assert operand.isVariable() : "register number out of bounds";
         assert intervalFor(operand) != null : "no interval found";
 
-        return splitChildAtOpId(intervalFor(operand), block.firstLirInstructionId(), LIRInstruction.OperandMode.Output);
+        return splitChildAtOpId(intervalFor(operand), block.lirBlock.firstLirInstructionId(), LIRInstruction.OperandMode.Output);
     }
 
     Interval intervalAtBlockEnd(BlockBegin block, CiValue operand) {
         assert operand.isVariable() : "register number out of bounds";
         assert intervalFor(operand) != null : "no interval found";
 
-        return splitChildAtOpId(intervalFor(operand), block.lastLirInstructionId() + 1, LIRInstruction.OperandMode.Output);
+        return splitChildAtOpId(intervalFor(operand), block.lirBlock.lastLirInstructionId() + 1, LIRInstruction.OperandMode.Output);
     }
 
     Interval intervalAtOpId(CiValue operand, int opId) {
@@ -1728,7 +1728,7 @@
         if (opId != -1) {
             if (C1XOptions.DetailedAsserts) {
                 BlockBegin block = blockForId(opId);
-                if (block.numberOfSux() <= 1 && opId == block.lastLirInstructionId()) {
+                if (block.numberOfSux() <= 1 && opId == block.lirBlock.lastLirInstructionId()) {
                     // check if spill moves could have been appended at the end of this block, but
                     // before the branch instruction. So the split child information for this branch would
                     // be incorrect.
@@ -1848,7 +1848,7 @@
             if (operand.isVariable()) {
                 OperandMode mode = OperandMode.Input;
                 BlockBegin block = blockForId(opId);
-                if (block.numberOfSux() == 1 && opId == block.lastLirInstructionId()) {
+                if (block.numberOfSux() == 1 && opId == block.lirBlock.lastLirInstructionId()) {
                     // generating debug information for the last instruction of a block.
                     // if this instruction is a branch, spill moves are inserted before this branch
                     // and so the wrong operand would be returned (spill moves at block boundaries are not
@@ -1857,7 +1857,7 @@
                     final LIRInstruction instr = block.lir().instructionsList().get(block.lir().instructionsList().size() - 1);
                     if (instr instanceof LIRBranch) {
                         if (block.lirBlock.liveOut.get(operandNumber(operand))) {
-                            opId = block.suxAt(0).firstLirInstructionId();
+                            opId = block.suxAt(0).lirBlock.firstLirInstructionId();
                             mode = OperandMode.Output;
                         }
                     }
@@ -2083,12 +2083,7 @@
         }
 
         printLir("After register number assignment", true);
-
         EdgeMoveOptimizer.optimize(ir.linearScanOrder());
-        if (C1XOptions.OptControlFlow) {
-            ControlFlowOptimizer.optimize(ir);
-        }
-
         printLir("After control flow optimization", false);
     }
 
@@ -2108,7 +2103,7 @@
             TTY.println("--- Basic Blocks ---");
             for (i = 0; i < blockCount(); i++) {
                 BlockBegin block = blockAt(i);
-                TTY.print("B%d [%d, %d, %d, %d] ", block.blockID, block.firstLirInstructionId(), block.lastLirInstructionId(), block.loopIndex(), block.loopDepth());
+                TTY.print("B%d [%d, %d, %d, %d] ", block.blockID, block.lirBlock.firstLirInstructionId(), block.lirBlock.lastLirInstructionId(), block.loopIndex(), block.loopDepth());
             }
             TTY.println();
             TTY.println();
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScanWalker.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScanWalker.java	Wed May 18 18:40:58 2011 +0200
@@ -262,9 +262,9 @@
 
         // Try to split at end of maxBlock. If this would be after
         // maxSplitPos, then use the begin of maxBlock
-        int optimalSplitPos = maxBlock.lastLirInstructionId() + 2;
+        int optimalSplitPos = maxBlock.lirBlock.lastLirInstructionId() + 2;
         if (optimalSplitPos > maxSplitPos) {
-            optimalSplitPos = maxBlock.firstLirInstructionId();
+            optimalSplitPos = maxBlock.lirBlock.firstLirInstructionId();
         }
 
         int minLoopDepth = maxBlock.loopDepth();
@@ -274,7 +274,7 @@
             if (cur.loopDepth() < minLoopDepth) {
                 // block with lower loop-depth found . split at the end of this block
                 minLoopDepth = cur.loopDepth();
-                optimalSplitPos = cur.lastLirInstructionId() + 2;
+                optimalSplitPos = cur.lirBlock.lastLirInstructionId() + 2;
             }
         }
         assert optimalSplitPos > allocator.maxOpId() || allocator.isBlockBegin(optimalSplitPos) : "algorithm must move split pos to block boundary";
@@ -334,7 +334,7 @@
                     if (doLoopOptimization) {
                         // Loop optimization: if a loop-end marker is found between min- and max-position :
                         // then split before this loop
-                        int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, minBlock.lastLirInstructionId() + 2);
+                        int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, minBlock.lirBlock.lastLirInstructionId() + 2);
                         if (C1XOptions.TraceLinearScanLevel >= 4) {
                             TTY.println("      loop optimization: loop end found at pos %d", loopEndPos);
                         }
@@ -353,8 +353,8 @@
                             }
                             assert loopBlock != minBlock : "loopBlock and minBlock must be different because block boundary is needed between";
 
-                            optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, loopBlock.lastLirInstructionId() + 2);
-                            if (optimalSplitPos == loopBlock.lastLirInstructionId() + 2) {
+                            optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, loopBlock.lirBlock.lastLirInstructionId() + 2);
+                            if (optimalSplitPos == loopBlock.lirBlock.lastLirInstructionId() + 2) {
                                 optimalSplitPos = -1;
                                 if (C1XOptions.TraceLinearScanLevel >= 4) {
                                     TTY.println("      loop optimization not necessary");
--- a/graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java	Wed May 18 18:40:58 2011 +0200
@@ -150,18 +150,6 @@
         out.println();
 
         out.print("flags ");
-        if (block.isSubroutineEntry()) {
-            out.print("\"sr\" ");
-        }
-        if (block.isBackwardBranchTarget()) {
-            out.print("\"bb\" ");
-        }
-        if (block.isParserLoopHeader()) {
-            out.print("\"plh\" ");
-        }
-        if (block.isCriticalEdgeSplit()) {
-            out.print("\"ces\" ");
-        }
         if (block.isLinearScanLoopHeader()) {
             out.print("\"llh\" ");
         }
@@ -170,9 +158,6 @@
         }
         out.println();
 
-        if (block.dominator() != null) {
-            out.print("dominator \"B").print(block.dominator().blockID).println('"');
-        }
         if (block.loopIndex() != -1) {
             out.print("loop_index ").println(block.loopIndex());
             out.print("loop_depth ").println(block.loopDepth());
--- a/graal/GraalCompiler/src/com/sun/c1x/debug/GraphvizPrinterObserver.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/debug/GraphvizPrinterObserver.java	Wed May 18 18:40:58 2011 +0200
@@ -23,6 +23,7 @@
 package com.sun.c1x.debug;
 
 import java.io.*;
+import java.util.regex.*;
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.vis.*;
@@ -38,6 +39,8 @@
  */
 public class GraphvizPrinterObserver implements CompilationObserver {
 
+    private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]");
+
     private final boolean pdf;
     private int n;
 
@@ -59,11 +62,15 @@
             String name = event.getMethod().holder().name();
             name = name.substring(1, name.length() - 1).replace('/', '.');
             name = name + "." + event.getMethod().name();
+
             String filename = name + "_" + (n++) + "_" + event.getLabel();
+            filename = INVALID_CHAR.matcher(filename).replaceAll("_");
+
+            OutputStream out = null;
             try {
                 if (pdf) {
-                    ByteArrayOutputStream out = new ByteArrayOutputStream();
-                    GraphvizPrinter printer = new GraphvizPrinter(out);
+                    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+                    GraphvizPrinter printer = new GraphvizPrinter(buffer);
                     if (C1XOptions.OmitDOTFrameStates) {
                         printer.addOmittedClass(FrameState.class);
                     }
@@ -71,24 +78,28 @@
                     printer.print(graph, true);
                     printer.end();
 
-                    FileOutputStream output = new FileOutputStream(filename + ".pdf");
-                    GraphvizRunner.process(GraphvizRunner.DOT_LAYOUT, new ByteArrayInputStream(out.toByteArray()), output, "pdf");
-                    output.close();
+                    out = new FileOutputStream(filename + ".pdf");
+                    GraphvizRunner.process(GraphvizRunner.DOT_LAYOUT, new ByteArrayInputStream(buffer.toByteArray()), out, "pdf");
                 } else {
-                    final FileOutputStream stream = new FileOutputStream(filename + ".gv");
+                    out = new FileOutputStream(filename + ".gv");
 
-                    GraphvizPrinter printer = new GraphvizPrinter(stream);
+                    GraphvizPrinter printer = new GraphvizPrinter(out);
                     if (C1XOptions.OmitDOTFrameStates) {
                         printer.addOmittedClass(FrameState.class);
                     }
                     printer.begin(name);
                     printer.print(graph, true);
                     printer.end();
-
-                    stream.close();
                 }
             } catch (IOException e) {
                 e.printStackTrace();
+            } finally {
+                if (out != null) {
+                    try {
+                        out.close();
+                    } catch (IOException e) {
+                    }
+                }
             }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/GraalCompiler/src/com/sun/c1x/debug/IdealGraphPrinter.java	Wed May 18 18:40:58 2011 +0200
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.c1x.debug;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+
+/**
+ * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the <a
+ * href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>.
+ */
+public class IdealGraphPrinter {
+
+    private static class Edge {
+        final int from;
+        final int to;
+        final int index;
+
+        Edge(int from, int to, int index) {
+            this.from = from;
+            this.to = to;
+            this.index = index;
+        }
+    }
+
+    private final HashSet<Class<?>> omittedClasses = new HashSet<Class<?>>();
+    private final PrintStream stream;
+
+    /**
+     * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
+     */
+    public IdealGraphPrinter(OutputStream stream) {
+        this.stream = new PrintStream(stream);
+    }
+
+    /**
+     * Adds a node class that is omitted in the output.
+     */
+    public void addOmittedClass(Class<?> clazz) {
+        omittedClasses.add(clazz);
+    }
+
+    /**
+     * Flushes any buffered output.
+     */
+    public void flush() {
+        stream.flush();
+    }
+
+    /**
+     * Starts a new graph document.
+     */
+    public void begin() {
+        stream.println("<graphDocument>");
+    }
+
+    /**
+     * Starts a new group of graphs with the given name, short name and method byte code index (BCI) as properties.
+     */
+    public void beginGroup(String name, String shortName, int bci) {
+        stream.println("<group>");
+        stream.printf(" <properties><p name='name'>%s</p></properties>%n", escape(name));
+        stream.printf(" <method name='%s' shortName='%s' bci='%d'/>%n", escape(name), escape(shortName), bci);
+    }
+
+    /**
+     * Ends the current group.
+     */
+    public void endGroup() {
+        stream.println("</group>");
+    }
+
+    /**
+     * Finishes the graph document and flushes the output stream.
+     */
+    public void end() {
+        stream.println("</graphDocument>");
+        flush();
+    }
+
+    /**
+     * Prints an entire {@link Graph} with the specified title, optionally using short names for nodes.
+     */
+    public void print(Graph graph, String title, boolean shortNames) {
+        stream.printf(" <graph name='%s'>%n", escape(title));
+
+        stream.println("  <nodes>");
+        List<Edge> edges = printNodes(graph.getNodes(), shortNames);
+        stream.println("  </nodes>");
+
+        stream.println("  <edges>");
+        for (Edge edge : edges) {
+            printEdge(edge);
+        }
+        stream.println("  </edges>");
+
+        stream.println(" </graph>");
+    }
+
+    private List<Edge> printNodes(Collection<Node> nodes, boolean shortNames) {
+        ArrayList<Edge> edges = new ArrayList<Edge>();
+
+        for (Node node : nodes) {
+            if (node == Node.Null || omittedClasses.contains(node)) {
+                continue;
+            }
+
+            String name;
+            if (shortNames) {
+                name = node.shortName();
+            } else {
+                name = node.toString();
+            }
+
+            stream.printf("   <node id='%d'><properties>", node.id());
+            stream.printf("<p name='idx'>%d</p>", node.id());
+            stream.printf("<p name='name'>%s</p>", escape(name));
+            stream.println("</properties></node>");
+
+            int index = 0;
+            for (Node predecessor : node.predecessors()) {
+                if (predecessor != Node.Null && !omittedClasses.contains(predecessor.getClass())) {
+                    edges.add(new Edge(predecessor.id(), node.id(), index));
+                }
+                index++;
+            }
+            for (Node input : node.inputs()) {
+                if (input != Node.Null && !omittedClasses.contains(input.getClass())) {
+                    edges.add(new Edge(input.id(), node.id(), index));
+                }
+                index++;
+            }
+        }
+
+        return edges;
+    }
+
+    private void printEdge(Edge edge) {
+        stream.printf("   <edge from='%d' to='%d' index='%d'/>%n", edge.from, edge.to, edge.index);
+    }
+
+    private String escape(String s) {
+        s = s.replace("&", "&amp;");
+        s = s.replace("<", "&lt;");
+        s = s.replace(">", "&gt;");
+        s = s.replace("\"", "&quot;");
+        s = s.replace("'", "&apos;");
+        return s;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/GraalCompiler/src/com/sun/c1x/debug/IdealGraphPrinterObserver.java	Wed May 18 18:40:58 2011 +0200
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.c1x.debug;
+
+import java.io.*;
+import java.net.*;
+import java.util.regex.*;
+
+import com.oracle.graal.graph.*;
+import com.sun.c1x.*;
+import com.sun.c1x.observer.*;
+import com.sun.c1x.value.*;
+
+/**
+ * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation that can be
+ * inspected with the <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>.
+ *
+ * @author Peter Hofer
+ */
+public class IdealGraphPrinterObserver implements CompilationObserver {
+
+    private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]");
+
+    private final String host;
+    private final int port;
+
+    private IdealGraphPrinter printer;
+    private OutputStream stream;
+    private Socket socket;
+
+    /**
+     * Creates a new {@link IdealGraphPrinterObserver} that writes output to a file named after the compiled method.
+     */
+    public IdealGraphPrinterObserver() {
+        this(null, -1);
+    }
+
+    /**
+     * Creates a new {@link IdealGraphPrinterObserver} that sends output to a remove IdealGraphVisualizer instance.
+     */
+    public IdealGraphPrinterObserver(String host, int port) {
+        this.host = host;
+        this.port = port;
+    }
+
+    @Override
+    public void compilationStarted(CompilationEvent event) {
+        assert (stream == null && printer == null);
+
+        if (!TTY.isSuppressed()) {
+            String name = event.getMethod().holder().name();
+            name = name.substring(1, name.length() - 1).replace('/', '.');
+            name = name + "." + event.getMethod().name();
+
+            if (host != null) {
+                openNetworkPrinter(name);
+            } else {
+                openFilePrinter(name);
+            }
+        }
+    }
+
+    private void openFilePrinter(String name) {
+        String filename = name + ".igv.xml";
+        filename = INVALID_CHAR.matcher(filename).replaceAll("_");
+
+        try {
+            stream = new FileOutputStream(filename);
+            printer = new IdealGraphPrinter(stream);
+            if (C1XOptions.OmitDOTFrameStates) {
+                printer.addOmittedClass(FrameState.class);
+            }
+            printer.begin();
+            printer.beginGroup(name, name, -1);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void openNetworkPrinter(String name) {
+        try {
+            socket = new Socket(host, port);
+            if (socket.getInputStream().read() == 'y') {
+                stream = socket.getOutputStream();
+            } else {
+                // server currently does not accept any input
+                socket.close();
+                socket = null;
+                return;
+            }
+
+            printer = new IdealGraphPrinter(stream);
+            if (C1XOptions.OmitDOTFrameStates) {
+                printer.addOmittedClass(FrameState.class);
+            }
+            printer.begin();
+            printer.beginGroup(name, name, -1);
+            printer.flush();
+            if (socket.getInputStream().read() != 'y') {
+                // server declines input for this method
+                socket.close();
+                socket = null;
+                stream = null;
+                printer = null;
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+
+            if (socket != null) {
+                try {
+                    socket.close();
+                } catch (IOException ioe) {
+                }
+                socket = null;
+            }
+            stream = null;
+            printer = null;
+        }
+    }
+
+    @Override
+    public void compilationEvent(CompilationEvent event) {
+        if (printer != null && event.getStartBlock() != null) {
+            Graph graph = event.getStartBlock().graph();
+            printer.print(graph, event.getLabel(), true);
+        }
+    }
+
+    @Override
+    public void compilationFinished(CompilationEvent event) {
+        if (printer != null) {
+            try {
+                printer.endGroup();
+                printer.end();
+
+                if (socket != null) {
+                    socket.close(); // also closes stream
+                } else {
+                    stream.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } finally {
+                printer = null;
+                stream = null;
+                socket = null;
+            }
+        }
+    }
+
+}
--- a/graal/GraalCompiler/src/com/sun/c1x/doc/IRInterpreter.txt	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-Current status and remaining issues in the IRInterpreter for HIR (September/18/09)
-=================================================================================
-
-Known Problems:
-With InterpretInvokedMethods disabled in C1XOptions:
-(2 fails)
-304: jtt/jvmni/JVM_GetClassContext01.java: (0) failed with false (expected true)
-557: jtt/reflect/Class_newInstance02.java: (0) failed with true (expected !java.lang.IllegalAccessException)
-
-The first problem is caused by the use of reflection in the IRInterpreter, and the calling stack is not as 
-expected by the JVM_GetClassContext01 test case. The second one is due to the private constructor of Class_newInstance01.
-Again, we are using reflection to call the newInstance() method to create an instance of class Class_newInstance01
-from the IRInterpreter class, which raises an IllegalAccessException.
-These are the only problems with all optimization levels.
-
-With InterpretInvokedMethods enabled in C1XOptions:
-(7 fails)
-245: jtt/except/Catch_StackOverflowError_03.java: (0) failed with !java.lang.InstantiationException (expected 0)
-304: jtt/jvmni/JVM_GetClassContext01.java: (0) failed with false (expected true)
-311: jtt/lang/Bridge_method01.java: (0) failed with unexpected com.sun.c1x.ci.CiBailout (expected 1)
-557: jtt/reflect/Class_newInstance02.java: (0) failed with true (expected !java.lang.IllegalAccessException)
-572: jtt/reflect/Invoke_virtual01.java: (1) failed with unexpected com.sun.c1x.ci.CiBailout (expected 55)
-575: jtt/reflect/Reflection_getCallerClass01.java: (1) failed with com.sun.c1x.debug.IRInterpreter$Evaluator (expected jtt.reflect.Reflection_getCallerClass01$Caller1)
-592: jtt/threads/Thread_isInterrupted04.java: (0) failed with false (expected true)
-
-Those are also due to reflection usage. The last problem has not been investigated.
\ No newline at end of file
--- a/graal/GraalCompiler/src/com/sun/c1x/doc/LoopPeeling.txt	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-Remaining Issues in the Loop Peeling optimization (September/18/09)
-===================================================================
-
-Known Problems:
-Currently loop peeling is not working when the loop has exception
-blocks. The algorithm has to be updated to handle these cases.
-
-Limitations:
-The algorithm performs loop peeling only on innermost loops. However,
-this is not a limitation. If one wants to peel the outermost loop(s),
-after peeling the innermost loop, an additional pass is necessary
-to update the blocks of the outermost loop, since after peeling
-the innermost loop, newer blocks are added to the CFG.
-
-Current status as of 09/18/2009
-After running using hir configuration, with optimization level 3, the
-following test cases produce wrong results:
-(4 fails)
-233: jtt/except/Catch_Loop01.java: (4) failed with unexpected com.sun.c1x.ci.CiBailout (expected -170)
-234: jtt/except/Catch_Loop02.java: (4) failed with unexpected com.sun.c1x.ci.CiBailout (expected -170)
-245: jtt/except/Catch_StackOverflowError_03.java: (0) failed with unexpected com.sun.c1x.ci.CiBailout (expected 0)
-272: jtt/hotpath/HP_array04.java: (80) failed with unexpected java.lang.AssertionError (expected 15645)
-
-All of them are related the known problem aforementioned.
-All the tests have the innermost loops peeled, and produce right results.
-
-Future Work:
-1- Add more loop tests to jtt. New tests should run the loop 0, 1, 2 or more iterations.
-
-2- Peel loops with exception blocks. 
-
-3- Currently, all innermost loops are peeled. Should we add logic to filter out some loops from loop peeling?
-
-4- Improve the way instructions are cloned. Now the algorithm visits the blocks in BFS order, which
-might produce errors depending on the order the blocks are visited.
-
-5- After inserting new phi instructions at exit blocks, we need to iterate over the remaining CFG to update instructions
-that may use the new phi. The way it's done now might me inefficient if the block has more than one exit node, since
-we can iterate over the same block more than once. This needs to be improved.
-
-5- For performance reasons, improve the way loops are represented, for example, to use a bitmap to represent the loop blocks.
-
-
--- a/graal/GraalCompiler/src/com/sun/c1x/doc/backend_open_issues.txt	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-Remaining Issues in the C1X backend (after the port July-Sep 09)
-======================================================================
-
-Maxine/Inspector Related Open Issues:
-   - Global stubs: Change calling convention (no longer write to callee stack as this makes stepping through the instructions for saving the parameters to global stubs impossible in the inspector)
-   - Reference maps: Corrently implement TargetMethod.prepareReferenceMap for C1XTargetMethod (checking for the need to stack walk a possible callee saved target method) and call it from Maxine
-   - Disassembler: The Maxine disassembler still does not correctly display every machine code instruction issued by C1X
-   - MaxRiRuntime and C1XTargetMethod have fixed dependencies on the X86 parts (instruction decoding, registers, calling convention), should be factored out
-
-Compile-Time Performance Improvements:
-   - Consider deleting the LIRItem class
-   - Make sure that LIROperand objects are not shared among LIR instructions and can therefore be directly modified by the LinearScan register allocator (no more need for the lazy creation of LIRAddress objects in the LIRInstruction class)
-   
-Run-Time Performance Improvements:
-   - Store mapping between machine code location and bytecode index in the target method (remove arguments from global stub calls), this decreases the number of necessary parameters especially for resolution instructions.
-   - Use Inline Cache on virtual method calls
-
-Better Portability:
-   - Integrate XIR; consider using CiLocation / CiConstant in XIR
-   - The JIT adapter frames should be a more general mechanism that receives two calling conventions (in form of an array of locations) and adapts between them automatically
-   - Have the possibility to register intrinsics by specifying XIR code
-   
\ No newline at end of file
--- a/graal/GraalCompiler/src/com/sun/c1x/doc/differences.txt	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-Differences between C1 and C1X, including upgrades and limitations
-(and some general information about C1)
-======================================================================
-
-StrictFP:
-   - C1X has removed the backend code to deal with the FPU stack, and therefore
-     requires SSE2 currently. StrictFP is still tracked in the front end.
-   - C1 will not inline methods with different strictfp-ness. C1X does not have this
-     limitation because it only targets SSE2 x86 processors.
-
-JSR/RET
-   - C1 will bail out if it encounters strange JSR/RET patterns
-       - recursive JSRs
-       - JSR regions that are shared with non-JSR code
-       - RET encountered out of JSR (would not verify)
-
-Exceptions
-   -  C1 will bailout if the code of an exception handler can be reached via normal
-      control flow.
-   => C1X might be extended to introduce a phi for the exception
-      object in this case.
-   -  C1 will bailout if an exception handler covers itself
-
-Verification
-   -  C1 does not rely on bytecode verification having been run. However, if it detects
-      type errors in its building the IR graph it will usually bail out.
-   -  C1 requires a bitmap of the bytecode, where a bit for
-      each byte of the bytecode indicates if the bytecode at that location starts a
-      basic block. It uses this to construct the basic block list in a single pass.
-   => Assertion failures and/or bugs in C1X that cause exceptions to be thrown bail out
-      the compilation instead of crashing the VM.
-   => C1X's BlockMap does not computes the basic block starts in one pass over the bytecode
-      and one pass over the successor lists.
-   => C1X computes the "stores in loops" only when loops are encountered in the CFG.
-      An option can select conservative mode (all locals stored in all loops) trades
-      faster parse speed for fewer optimization opportunities
-   => C1X includes an IRChecker that typechecks the entire IR and checks for CFG
-      consistency that can be run after each pass.
-
-Constants
-   => C1X allows unrestricted use of object constants throughout the code, including
-      folding reads of static final fields that reference objects.
-
-Pinning
-   => C1X pins fewer instructions than C1
-   ** C1X will eventually allow certain kinds of instructions to float outside the CFG
-      and be scheduled with a C2-lite scheduling pass.
-
-Synchronization
-   -  C1 will refuse to compile methods with unbalanced synchronization. This property is
-      computed by the bytecode verifier and supplied to C1.
-   ** C1X will not rely on the bytecode verifier to compute this but should do so itself.
-   => C1 relied on the backend to generate synchronization code for the root method's
-      synchronization operations. C1X inserts code into the start block and generates
-      and exception handler to do this explicitly.
-
-Optimizations
-   => C1X has many more options to turn on individual passes, parts of passes, approximations,
-      etc. It is designed to have three optimization levels:
-      0 = super-fast: essentially no optimization
-      1 = fast:       inlining, constant folding, and local optimizations
-      2 = optimized:  inlining, constant folding, local and global optimizations, including
-                      iterative versions of all algorithms
-   ** Planned optimizations for C1X that C1 does not have:
-      TypeCheckElimination:        remove redundant casts and devirtualize more call sites
-      ArrayBoundsCheckElimination: remove redundant array bounds checks and/or restructure
-                                   code to deoptimize when bounds checks within loops will fail
-      LoopPeeling:                 replicate the first iteration of a loop
-      LoopUnrolling:               replicate the body of certain shapes of loops
-      LoopInvariantCodeMotion:     move invariant code out of a loop
-      ProfileGuidedInlining:       use receiver method profiles to emit guarded inlines
-      ProfileGuidedBlockLayout:    use profiling information for code placement
-      Peephole:                    peephole optimize backend output
-
-Block Merging
-   ** C1X will replace branches to blocks with a single Goto with a branch to the
-      block's successor, if the blocks cannot be merged otherwise.
-
-Constant Folding / Strength reduction
-   -  C1 had some of its strength reduction logic built into the GraphBuilder because
-      the Canonicalizer could not return multiple instructions.
-   => C1X added this ability, moved the logic to Canonicalizer, and added a few new
-      strength reductions.
-   => C1X should have an interface for doing folding of @FOLD method calls
-   => C1X folds many intrinsic operations that don't have side effects
-   => C1X folds all the basic floating point operations
-   => C1X strength reduces (e >> C >> K) to (e >> (C + K)) when C and K are constant
-   => Multiplies of power-of-2 constants are reduced to shifts in the canonicalizer
-      (instead of the backend)
-   ** C1X will be able to run a global sparse conditional constant propagation phase
-      to catch any missed canonicalization opportunities after graph building.
-
-Switches
-   -  C1 did not detect back edges in tableswitch/lookupswitch default branches
-   => C1X does detect these back edges
-   => C1X moved the canonicalization code of 1 and 2 branch switches to canonicalizer,
-      where it belongs
-
-Inlining
-   -  C1 cannot inline:
-      -  native methods (or their stubs), except some intrinsics
-      -  methods whose class has not been initialized
-      -  methods with unbalanced monitors
-      -  methods with JSRs (this is probably technically possible now)
-
-   -  C1 will not inline:
-      -  methods with exception handlers (optional)
-      -  synchronized methods (optional)
-      -  if the maximum inline depth is reached (default = 9)
-      -  if the maximum recursive inline depth is reached (default = 1)
-      -  if the callee is larger than the maximum inline size (reduced to 90% at each level, starting at 35)
-      -  constructors for subclasses of Throwable
-      -  if the strictfp-ness of the callee is different than the caller (on x87)
-      -  abstract methods
-      -  synchronized intrinsics
-
-Load/store elimination
-   => C1X may eliminate loads of static fields, which C1 did not
-   => C1X distinguishes loads/stores to different fields in MemoryBuffer
-   => C1X assumes that RiField instances are unique when .isLoaded() is true
-
-Local/Global Value Numbering
-   => C1X improved local load elimination and no longer value numbers fields, reducing the
-      logic necessary in ValueMap, simplifying it and improving its performance.
-   => C1X reuses the same simplified ValueMap for GVN. Since heap accesses are no longer
-      value numbered, the logic to kill values is unnecessary, greatly simplifying
-      GVN.
-   ** A global version of load elimination will compensate for this loss in the future.
-   => C1X value numbers are always or'd with a high order bit when value numbering is possible
-      to prevent value numbering failing if the value number is accidentally 0.
-
-Nullcheck elimination
-   => A new flag, NonNull, indicates instructions that produce values that are guaranteed
-      to be non-null (e.g. NewXXX and Local 0, NullCheck). Instructions that require null
-      checks check this flag for their inputs in their constructors, eliminating most
-      redundant null checks immediately, without requiring the NullCheckEliminator to run.
-   => C1X uses a more efficient block ordering for null check elimination. The first pass is
-      optimistic and attempts to visit the blocks in reverse post-order. For acyclic graphs,
-      this almost always succeeds, requiring no iteration. Full iterative data flow analysis
-      can be enabled separately. Bitmaps used during the fixpoint calculation are much
-      smaller due to local numbering of instructions (as opposed to global IDs).
-   ** C1X will recognize If's that check against null and propagate the non-nullness across
-      the appropriate branches.
-
-BlockListBuilder
-   -  C1 had a vestigial loop map in BlockListBuilder which was not really used.
-   => C1X does not need to compute a complete loop map in order to do selective phi creation,
-      it builds the "storesInLoops" BitMap in BlockMap.
-
-Types
-   => C1X adds the declared type of method parameters to Local instructions, which
-      may help with devirtualization
-   => C1X makes local 0 of instance methods non-null at the start
-
--- a/graal/GraalCompiler/src/com/sun/c1x/doc/performance.txt	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-Issues that can be addressed for improving performance in C1X
-----------------------------------------------------------------
-
-- indicates not done
-* indicates done
-
-Backend:
-	- better handling of constants, especially immediates
-	- (non XIR) checkcast, instanceof: use nullity
-	- (non XIR) checkcast, instanceof: emit fastpath direct compare
-	- use LEA instruction on x86
-	- recognize pointer arithmetic addressing modes
-	- recognize multiply by 3, 5, 9 and emit lea rk, [rs, rs*2], etc
-	- Maxine XIR: make direct runtime calls instead of through global stub
-	- Maxine XIR: implement inline allocation
-	- Maxine XIR: implement biased locking fastpath
-	- Maxine XIR: faster subtype checks for classes, leaves
-	- Maxine XIR: make use of XirSite nullity, range check information
-	- better handling of tableswitch bytecode
-	- better handling of two operand LIR form
-	- Make the following bytecode implementations inline:
-		- f2i f2l f2d d2i d2l d2f (SSE2)
-		* lrem ldiv (64 bit)
-		- fneg dneg
-	- Make the following bytecode implementations global stubs:
-		- frem drem
-	- Global stubs: use EAX for return value as normal instead of [rsp - 16]
-    - Emit direct call to runtime for new instance, monitorenter, monitorexit
-
-	* XIR: expose nullity, range checkness across XIR interface
-	- XIR: make use of CSE'd array length
-	- XIR: generate special if-instanceof XIR variant with label parameters
-    - Optimize special cases of bytecodes:
-        - (MIN_INT / -1) in IDIV,IREM
-        - (MIN_LONG / -1) in LDIV,LREM
-        - (-infinity, Nan, +infinity) in F2I, F2L, D2I, D2L
-
-
-Frontend:
-    - Remove redundant null check branches in NullCheckEliminator
-	- XIR: implement HIR -> HIR xir translation
-	- Refactor exception edges to allow removal, optimization
-	- Implement typecast elimination
-	- Implement constant propagation
-	- Implement GVN of memory loads / stores
-	- Implement memory reordering
-	- Implement loop invariant code motion
-	- Optimize endianness conversions and endian-writes
-	      (e.g. (x >> 24 & 0xff) | (....)) and a[0] = x >> 24 ...
-	- Finish loop peeling
-	- Implement loop unrolling
-	- Allow value numbering of constant loads
-	- Finish loop peeling
-	- Guarded and multiple inlining
-	- Maxine: speculative leaf class and leaf method assumption
-	- Maxine: adjust static / dynamic inlining heuristics
-		  (e.g. static: trivial methods only in cold spots)
-    - Aggressive optimization of array copy
-
-Compilation speed:
-    - Make special iterators for LIROperand input, temp, output
-    - Add analysisInfo field to Value and use in NullCheckEliminator
-	- Remove RiConstantPool, cpi from unresolved HIR instructions (move to RiField, RiMethod)
-	- Use BlockList instead of ArrayList<Block> where appropriate
-	- Use FrameState instead of ValueStack
-	- Remove exceptionHandlers, make DebugInfo hold FrameState, CiCodePos,
-		exception flags and exception handlers
-	- Clean up and simplify LIRInstruction constructor
-	- Create fewer LIRAddresses
-	- Simplify LIRGenerator logic (forcing of loading, etc)
-	- LIROperand: split into virtual register table?
-	- Cleanup assembler and remove dead code, useless assertions
-	- Chain assembler byte buffers and only assemble at the end
-	- Pick optimal initial assembler byte buffer size
-	- Pick good initial sizes for LinearScan data structures
-	- Remove unnecessary uses of ArrayList and replace with arrays or other list
-	- Use iteration over ArrayList instead of explicit loop
-	- Revisit manual editing / removal of items from ArrayList
-	- Remove non-XIR backend
-	- Pre-assemble XIR for backend
-
-	* Initialize compilation-unique instruction id's lazily with thread local compilation
-	* Remove dead LIROpcodes
-	* Remove dead code in LIRGenerator, X86LIRGenerator, LIRAssembler, X86LIRAssembler
-		(remove commented out code)
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/BlockMap.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/BlockMap.java	Wed May 18 18:40:58 2011 +0200
@@ -615,42 +615,4 @@
 
         out.print("loop_depth ").println(Integer.bitCount(block.loops));
     }
-
-//
-//    private static StringBuilder append(StringBuilder sb, BlockBegin block) {
-//        return sb.append('B').append(block.blockID).append('@').append(block.bci());
-//    }
-//
-//    @Override
-//    public String toString() {
-//        StringBuilder sb = new StringBuilder();
-//        for (int bci = 0; bci < blockMap.length; ++bci) {
-//            BlockBegin block = blockMap[bci];
-//            if (block != null) {
-//                append(sb, block);
-//                if (loopBlocks != null && loopBlocks.contains(block)) {
-//                    sb.append("{loop-header}");
-//                }
-//                if (successorMap != null) {
-//                    BlockBegin[] succs = successorMap[bci];
-//                    if (succs != null && succs.length > 0) {
-//                        sb.append(" ->");
-//                        for (BlockBegin succ : succs) {
-//                            append(sb.append(' '), succ);
-//                        }
-//                    }
-//                }
-//                Collection<BlockBegin> handlers = getHandlers(block);
-//                if (!handlers.isEmpty()) {
-//                    sb.append(" xhandlers{");
-//                    for (BlockBegin h : handlers) {
-//                        append(sb, h).append(' ');
-//                    }
-//                    sb.append('}');
-//                }
-//                sb.append(String.format("%n"));
-//            }
-//        }
-//        return sb.toString();
-//    }
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/BlockUtil.java	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.sun.c1x.graph;
-
-import java.util.*;
-
-import com.sun.c1x.ir.*;
-
-/**
- * The {@code BlockUtil} class contains a number of utilities for manipulating a CFG of basic blocks.
- */
-public class BlockUtil {
-
-    /**
-     * Disconnects the specified block from all other blocks.
-     * @param block the block to remove from the graph
-     */
-    public static void disconnectFromGraph(BlockBegin block) {
-        ArrayList<Instruction> preds = new ArrayList<Instruction>(block.blockPredecessors());
-        for (Instruction p : preds) {
-            p.block().end().blockSuccessors().remove(block);
-        }
-        block.end().clearSuccessors();
-    }
-}
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Wed May 18 18:40:58 2011 +0200
@@ -147,11 +147,6 @@
             flags |= Flag.NoSafepoints.mask;
         }
 
-        // 1. create the start block
-        ir.startBlock = new BlockBegin(0, ir.nextBlockNumber(), graph);
-        BlockBegin startBlock = ir.startBlock;
-        graph.root().setStart(startBlock);
-
         // 2. compute the block map, setup exception handlers and get the entrypoint(s)
         BlockMap blockMap = compilation.getBlockMap(rootMethod);
 
@@ -166,7 +161,11 @@
             blockList[block.startBci] = blockBegin;
         }
 
-        BlockBegin stdEntry = blockList[0];
+
+        // 1. create the start block
+        ir.startBlock = new BlockBegin(0, ir.nextBlockNumber(), graph);
+        BlockBegin startBlock = ir.startBlock;
+        graph.root().setStart(startBlock);
         curBlock = startBlock;
 
         RiExceptionHandler[] handlers = rootMethod.exceptionHandlers();
@@ -192,30 +191,30 @@
         lastInstr = startBlock;
         lastInstr.appendNext(null, -1);
 
+        BlockBegin entryBlock = blockList[0];
         if (isSynchronized(rootMethod.accessFlags())) {
             // 4A.1 add a monitor enter to the start block
             rootMethodSynchronizedObject = synchronizedObject(frameState, compilation.method);
             genMonitorEnter(rootMethodSynchronizedObject, Instruction.SYNCHRONIZATION_ENTRY_BCI);
             // 4A.2 finish the start block
-            finishStartBlock(startBlock, stdEntry);
+            finishStartBlock(startBlock, entryBlock);
 
             // 4A.3 setup an exception handler to unlock the root method synchronized object
             syncHandler = new BlockBegin(Instruction.SYNCHRONIZATION_ENTRY_BCI, ir.nextBlockNumber(), graph);
-            syncHandler.setBlockFlag(BlockBegin.BlockFlag.IsOnWorkList);
-            syncHandler.setBlockFlag(BlockBegin.BlockFlag.DefaultExceptionHandler);
+            markOnWorkList(syncHandler);
 
             ExceptionHandler h = new ExceptionHandler(new CiExceptionHandler(0, rootMethod.code().length, -1, 0, null));
             h.setEntryBlock(syncHandler);
             addExceptionHandler(h);
         } else {
             // 4B.1 simply finish the start block
-            finishStartBlock(startBlock, stdEntry);
+            finishStartBlock(startBlock, entryBlock);
         }
 
         // 5. SKIPPED: look for intrinsics
 
         // 6B.1 do the normal parsing
-        addToWorkList(stdEntry);
+        addToWorkList(entryBlock);
         iterateAllBlocks();
 
         if (syncHandler != null && syncHandler.stateBefore() != null) {
@@ -224,6 +223,26 @@
         }
     }
 
+    private Set<BlockBegin> blocksOnWorklist = new HashSet<BlockBegin>();
+
+    private void markOnWorkList(BlockBegin block) {
+        blocksOnWorklist.add(block);
+    }
+
+    private boolean isOnWorkList(BlockBegin block) {
+        return blocksOnWorklist.contains(block);
+    }
+
+    private Set<BlockBegin> blocksVisited = new HashSet<BlockBegin>();
+
+    private void markVisited(BlockBegin block) {
+        blocksVisited.add(block);
+    }
+
+    private boolean isVisited(BlockBegin block) {
+        return blocksVisited.contains(block);
+    }
+
     private void finishStartBlock(BlockBegin startBlock, BlockBegin stdEntry) {
         assert curBlock == startBlock;
         FrameState stateAfter = frameState.create(bci());
@@ -402,7 +421,7 @@
         ExceptionHandler newHandler = new ExceptionHandler(handler);
 
         // fill in exception handler subgraph lazily
-        if (!entry.wasVisited()) {
+        if (!isVisited(entry)) {
             addToWorkList(entry);
         } else {
             // This will occur for exception handlers that cover themselves. This code
@@ -1113,24 +1132,24 @@
 
             // remove blocks that have no predecessors by the time it their bytecodes are parsed
             if (b.blockPredecessors().size() == 0) {
-                b.setWasVisited(true);
+                markVisited(b);
                 continue;
             }
 
-            if (!b.wasVisited()) {
-                b.setWasVisited(true);
+            if (!isVisited(b)) {
+                markVisited(b);
                 // now parse the block
                 curBlock = b;
                 frameState.initializeFrom(b.stateBefore());
                 lastInstr = b;
                 b.appendNext(null, -1);
 
-                iterateBytecodesForBlock(b.bci(), false);
+                iterateBytecodesForBlock(b.bci());
             }
         }
     }
 
-    private BlockEnd iterateBytecodesForBlock(int bci, boolean inliningIntoCurrentBlock) {
+    private BlockEnd iterateBytecodesForBlock(int bci) {
         assert frameState != null;
         stream.setBCI(bci);
 
@@ -1142,14 +1161,6 @@
 
         while (bci < endBCI) {
             BlockBegin nextBlock = blockAtOrNull(bci);
-            if (bci == 0 && inliningIntoCurrentBlock) {
-                if (!nextBlock.isParserLoopHeader()) {
-                    // Ignore the block boundary of the entry block of a method
-                    // being inlined unless the block is a loop header.
-                    nextBlock = null;
-                    blockStart = false;
-                }
-            }
             if (nextBlock != null && nextBlock != block) {
                 // we fell through to the next block, add a goto and break
                 end = new Goto(nextBlock, null, false, graph);
@@ -1476,8 +1487,8 @@
      * @param block the block to add to the work list
      */
     private void addToWorkList(BlockBegin block) {
-        if (!block.isOnWorkList()) {
-            block.setOnWorkList(true);
+        if (!isOnWorkList(block)) {
+            markOnWorkList(block);
             sortIntoWorkList(block);
         }
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Wed May 18 18:40:58 2011 +0200
@@ -89,7 +89,6 @@
     private void buildGraph() {
         // Graph builder must set the startBlock and the osrEntryBlock
         new GraphBuilder(compilation, this, compilation.graph).build();
-        assert startBlock != null;
         verifyAndPrint("After graph building");
 
         if (C1XOptions.PrintCompilation) {
@@ -168,8 +167,6 @@
         // create new successor and mark it for special block order treatment
         BlockBegin newSucc = new BlockBegin(bci, nextBlockNumber(), compilation.graph);
 
-        newSucc.setCriticalEdgeSplit(true);
-
         // This goto is not a safepoint.
         Goto e = new Goto(target, null, false, compilation.graph);
         newSucc.appendNext(e, bci);
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java	Wed May 18 18:40:58 2011 +0200
@@ -81,13 +81,8 @@
      */
     public enum BlockFlag {
         StandardEntry,
-        SubroutineEntry,
         BackwardBranchTarget,
-        IsOnWorkList,
-        WasVisited,
-        DefaultExceptionHandler,
         ParserLoopHeader,
-        CriticalEdgeSplit,
         LinearScanLoopHeader,
         LinearScanLoopEnd;
 
@@ -106,13 +101,11 @@
 
     private int depthFirstNumber;
     private int linearScanNumber;
-    private int loopDepth;
-    private int loopIndex;
 
     private BlockBegin dominator;
 
     // LIR block
-    public LIRBlock lirBlock;
+    public final LIRBlock lirBlock = new LIRBlock();
 
     /**
      * Constructs a new BlockBegin at the specified bytecode index.
@@ -125,7 +118,6 @@
         this.blockID = blockID;
         depthFirstNumber = -1;
         linearScanNumber = -1;
-        loopIndex = -1;
         setBCI(bci);
     }
 
@@ -143,14 +135,6 @@
     }
 
     /**
-     * Gets the dominator of this block.
-     * @return the dominator block
-     */
-    public BlockBegin dominator() {
-        return dominator;
-    }
-
-    /**
      * Sets the dominator block for this block.
      * @param dominator the dominator for this block
      */
@@ -179,7 +163,7 @@
      * @return the loop depth
      */
     public int loopDepth() {
-        return loopDepth;
+        return lirBlock.loopDepth;
     }
 
     /**
@@ -187,7 +171,7 @@
      * @return the loop index
      */
     public int loopIndex() {
-        return loopIndex;
+        return lirBlock.loopIndex;
     }
 
     public void setDepthFirstNumber(int depthFirstNumber) {
@@ -200,11 +184,11 @@
     }
 
     public void setLoopDepth(int loopDepth) {
-        this.loopDepth = loopDepth;
+        this.lirBlock.loopDepth = loopDepth;
     }
 
     public void setLoopIndex(int loopIndex) {
-        this.loopIndex = loopIndex;
+        this.lirBlock.loopIndex = loopIndex;
     }
 
     /**
@@ -352,12 +336,6 @@
         FrameState existingState = stateBefore();
 
         if (existingState == null) {
-            // this is the first state for the block
-            if (wasVisited()) {
-                // this can happen for complex jsr/ret patterns; just bail out
-                throw new CiBailout("jsr/ret too complex");
-            }
-
             // copy state because it is modified
             FrameState duplicate = newState.duplicate(bci());
             assert duplicate.bci == bci() : "duplicate.bci=" + duplicate.bci + " my bci=" + bci();
@@ -389,10 +367,6 @@
             assert existingState.localsSize() == newState.localsSize();
             assert existingState.stackSize() == newState.stackSize();
 
-            if (wasVisited() && !isParserLoopHeader()) {
-                throw new CiBailout("jsr/ret too complicated");
-            }
-
             existingState.merge(this, newState);
         }
     }
@@ -426,46 +400,6 @@
         }
     }
 
-    public boolean isBackwardBranchTarget() {
-        return checkBlockFlag(BlockFlag.BackwardBranchTarget);
-    }
-
-    public void setBackwardBranchTarget(boolean value) {
-        setBlockFlag(BlockFlag.BackwardBranchTarget, value);
-    }
-
-    public boolean isCriticalEdgeSplit() {
-        return checkBlockFlag(BlockFlag.CriticalEdgeSplit);
-    }
-
-    public void setCriticalEdgeSplit(boolean value) {
-        setBlockFlag(BlockFlag.CriticalEdgeSplit, value);
-    }
-
-    public boolean isSubroutineEntry() {
-        return checkBlockFlag(BlockFlag.SubroutineEntry);
-    }
-
-    public void setSubroutineEntry() {
-        setBlockFlag(BlockFlag.SubroutineEntry);
-    }
-
-    public boolean isOnWorkList() {
-        return checkBlockFlag(BlockFlag.IsOnWorkList);
-    }
-
-    public void setOnWorkList(boolean value) {
-        setBlockFlag(BlockFlag.IsOnWorkList, value);
-    }
-
-    public boolean wasVisited() {
-        return checkBlockFlag(BlockFlag.WasVisited);
-    }
-
-    public void setWasVisited(boolean value) {
-        setBlockFlag(BlockFlag.WasVisited, value);
-    }
-
     public boolean isParserLoopHeader() {
         return checkBlockFlag(BlockFlag.ParserLoopHeader);
     }
@@ -478,18 +412,10 @@
         return checkBlockFlag(BlockFlag.LinearScanLoopHeader);
     }
 
-    public void setLinearScanLoopHeader(boolean value) {
-        setBlockFlag(BlockFlag.LinearScanLoopHeader, value);
-    }
-
     public boolean isLinearScanLoopEnd() {
         return checkBlockFlag(BlockFlag.LinearScanLoopEnd);
     }
 
-    public void setLinearScanLoopEnd(boolean value) {
-        setBlockFlag(BlockFlag.LinearScanLoopEnd, value);
-    }
-
     private void setBlockFlag(BlockFlag flag, boolean value) {
         if (value) {
             setBlockFlag(flag);
@@ -498,12 +424,6 @@
         }
     }
 
-    public void copyBlockFlags(BlockBegin other) {
-        copyBlockFlag(other, BlockBegin.BlockFlag.ParserLoopHeader);
-        copyBlockFlag(other, BlockBegin.BlockFlag.SubroutineEntry);
-        copyBlockFlag(other, BlockBegin.BlockFlag.WasVisited);
-    }
-
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
@@ -587,9 +507,6 @@
     }
 
     public LIRBlock lirBlock() {
-        if (lirBlock == null) {
-            lirBlock = new LIRBlock();
-        }
         return lirBlock;
     }
 
@@ -605,21 +522,6 @@
         return (Instruction) predecessors().get(j);
     }
 
-    public int firstLirInstructionId() {
-        return lirBlock.firstLirInstructionID;
-    }
-
-    public void setFirstLirInstructionId(int firstLirInstructionId) {
-        lirBlock.firstLirInstructionID = firstLirInstructionId;
-    }
-
-    public int lastLirInstructionId() {
-        return lirBlock.lastLirInstructionID;
-    }
-
-    public void setLastLirInstructionId(int lastLirInstructionId) {
-        lirBlock.lastLirInstructionID = lastLirInstructionId;
-    }
 
     public boolean isPredecessor(Instruction block) {
         return predecessors().contains(block);
@@ -632,18 +534,9 @@
 
         // print flags
         StringBuilder sb = new StringBuilder(8);
-        if (isSubroutineEntry()) {
-            sb.append('s');
-        }
         if (isParserLoopHeader()) {
             sb.append("LH");
         }
-        if (isBackwardBranchTarget()) {
-            sb.append('b');
-        }
-        if (wasVisited()) {
-            sb.append('V');
-        }
         if (sb.length() != 0) {
             out.print('(').print(sb.toString()).print(')');
         }
@@ -659,11 +552,6 @@
             }
         }
 
-        // print dominator block
-        if (dominator() != null) {
-            out.print(" dom B").print(dominator().blockID);
-        }
-
         // print predecessors
         if (!blockPredecessors().isEmpty()) {
             out.print(" pred:");
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java	Wed May 18 18:40:58 2011 +0200
@@ -126,7 +126,6 @@
         }
 
         computeOrder(startBlock);
-        computeDominators();
 
         printBlocks();
         assert verify();
@@ -144,7 +143,6 @@
         if (C1XOptions.TraceLinearScanLevel >= 3) {
             TTY.println("Counting edges for block B%d%s", cur.blockID, parent == null ? "" : " coming from B" + parent.blockID);
         }
-        assert cur.dominator() == null : "dominator already initialized";
 
         if (isActive(cur)) {
             if (C1XOptions.TraceLinearScanLevel >= 3) {
@@ -220,8 +218,8 @@
             if (C1XOptions.TraceLinearScanLevel >= 3) {
                 TTY.println("Processing loop from B%d to B%d (loop %d):", loopStart.blockID, loopEnd.blockID, loopIdx);
             }
-            assert loopEnd.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd) : "loop end flag must be set";
-            assert loopStart.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) : "loop header flag must be set";
+            assert loopEnd.isLinearScanLoopEnd() : "loop end flag must be set";
+            assert loopStart.isLinearScanLoopHeader() : "loop header flag must be set";
             assert loopIdx >= 0 && loopIdx < numLoops : "loop index not set";
             assert workList.isEmpty() : "work list must be empty before processing";
 
@@ -317,40 +315,6 @@
         } while (!workList.isEmpty());
     }
 
-    private BlockBegin commonDominator(BlockBegin a, BlockBegin b) {
-        assert a != null && b != null : "must have input blocks";
-
-        dominatorBlocks.clearAll();
-        while (a != null) {
-            dominatorBlocks.set(a.blockID);
-            assert a.dominator() != null || a == linearScanOrder.get(0) : "dominator must be initialized";
-            a = a.dominator();
-        }
-        while (b != null && !dominatorBlocks.get(b.blockID)) {
-            assert b.dominator() != null || b == linearScanOrder.get(0) : "dominator must be initialized";
-            b = b.dominator();
-        }
-
-        assert b != null : "could not find dominator";
-        return b;
-    }
-
-    private void computeDominator(BlockBegin cur, BlockBegin parent) {
-        if (cur.dominator() == null) {
-            if (C1XOptions.TraceLinearScanLevel >= 4) {
-                TTY.println("DOM: initializing dominator of B%d to B%d", cur.blockID, parent.blockID);
-            }
-            cur.setDominator(parent);
-
-        } else if (!(cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) && parent.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd))) {
-            if (C1XOptions.TraceLinearScanLevel >= 4) {
-                TTY.println("DOM: computing dominator of B%d: common dominator of B%d and B%d is B%d", cur.blockID, parent.blockID, cur.dominator().blockID, commonDominator(cur.dominator(), parent).blockID);
-            }
-            assert cur.numberOfPreds() > 1 : "";
-            cur.setDominator(commonDominator(cur.dominator(), parent));
-        }
-    }
-
     private int computeWeight(BlockBegin cur) {
         BlockBegin singleSux = null;
         if (cur.numberOfSux() == 1) {
@@ -365,21 +329,14 @@
         // this is necessary for the (very rare) case that two successive blocks have
         // the same loop depth, but a different loop index (can happen for endless loops
         // with exception handlers)
-        if (!cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader)) {
+        if (!cur.isLinearScanLoopHeader()) {
             weight |= (1 << curBit);
         }
         curBit--;
 
         // loop end blocks (blocks that end with a backward branch) are added
         // after all other blocks of the loop.
-        if (!cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd)) {
-            weight |= (1 << curBit);
-        }
-        curBit--;
-
-        // critical edge split blocks are preferred because then they have a greater
-        // probability to be completely empty
-        if (cur.isCriticalEdgeSplit()) {
+        if (!cur.isLinearScanLoopEnd()) {
             weight |= (1 << curBit);
         }
         curBit--;
@@ -493,7 +450,6 @@
 
             cur.allSuccessorsDo(false, new BlockClosure() {
                 public void apply(BlockBegin block) {
-                    computeDominator(block, cur);
                     if (readyForProcessing(block)) {
                         sortIntoWorkList(block);
                     }
@@ -502,55 +458,6 @@
         } while (workList.size() > 0);
     }
 
-    private boolean computeDominatorsIter() {
-        boolean changed = false;
-        int numBlocks = linearScanOrder.size();
-
-        assert linearScanOrder.get(0).dominator() == null : "must not have dominator";
-        assert linearScanOrder.get(0).numberOfPreds() == 0 : "must not have predecessors";
-        for (int i = 1; i < numBlocks; i++) {
-            BlockBegin block = linearScanOrder.get(i);
-
-            assert block.numberOfPreds() > 0;
-            BlockBegin dominator = block.predAt(0).block();
-
-            int numPreds = block.numberOfPreds();
-            for (int j = 1; j < numPreds; j++) {
-                BlockBegin curPred = block.predAt(j).block();
-                dominator = commonDominator(dominator, curPred);
-            }
-
-            if (dominator != block.dominator()) {
-                if (C1XOptions.TraceLinearScanLevel >= 4) {
-                    TTY.println("DOM: updating dominator of B%d from B%d to B%d", block.blockID, block.dominator().blockID, dominator.blockID);
-                }
-                block.setDominator(dominator);
-                changed = true;
-            }
-        }
-        return changed;
-    }
-
-    private void computeDominators() {
-        if (C1XOptions.TraceLinearScanLevel >= 3) {
-            TTY.println("----- computing dominators (iterative computation required: %b)", iterativeDominators);
-        }
-
-        // iterative computation of dominators is only required for methods with non-natural loops
-        // and OSR-methods. For all other methods : the dominators computed when generating the
-        // linear scan block order are correct.
-        if (iterativeDominators) {
-            do {
-                if (C1XOptions.TraceLinearScanLevel >= 1) {
-                    TTY.println("DOM: next iteration of fix-point calculation");
-                }
-            } while (computeDominatorsIter());
-        }
-
-        // check that dominators are correct
-        assert !computeDominatorsIter() : "fix point not reached";
-    }
-
     public void printBlocks() {
         if (C1XOptions.TraceLinearScanLevel >= 2) {
             TTY.println("----- loop information:");
@@ -568,15 +475,8 @@
             for (BlockBegin cur : linearScanOrder) {
                 TTY.print(String.format("%4d: B%02d    loop: %2d  depth: %2d", cur.linearScanNumber(), cur.blockID, cur.loopIndex(), cur.loopDepth()));
 
-                TTY.print(cur.isCriticalEdgeSplit() ? " ce" : "   ");
-                TTY.print(cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) ? " lh" : "   ");
-                TTY.print(cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd) ? " le" : "   ");
-
-                if (cur.dominator() != null) {
-                    TTY.print("    dom: B%d ", cur.dominator().blockID);
-                } else {
-                    TTY.print("    dom: null ");
-                }
+                TTY.print(cur.isLinearScanLoopHeader() ? " lh" : "   ");
+                TTY.print(cur.isLinearScanLoopEnd() ? " le" : "   ");
 
                 if (cur.numberOfPreds() > 0) {
                     TTY.print("    preds: ");
@@ -634,17 +534,7 @@
                 if (cur.loopDepth() == begin.loopDepth()) {
                     assert cur.loopIndex() == begin.loopIndex() || cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) : "successing blocks with same loop depth must have same loop index";
                 }
-
-                assert cur.dominator().linearScanNumber() <= begin.linearScanNumber() : "dominator must be before predecessors";
             }
-
-            // check dominator
-            if (i == 0) {
-                assert cur.dominator() == null : "first block has no dominator";
-            } else {
-                assert cur.dominator() != null : "all but first block must have dominator";
-            }
-            assert cur.numberOfPreds() != 1 || cur.dominator() == cur.predAt(0).block() : "Single predecessor must also be dominator";
         }
 
         // check that all loops are continuous
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Value.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Value.java	Wed May 18 18:40:58 2011 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.graph.*;
 import com.sun.c1x.debug.*;
-import com.sun.c1x.opt.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
 
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRAssembler.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIRAssembler.java	Wed May 18 18:40:58 2011 +0200
@@ -109,9 +109,6 @@
     }
 
     void emitBlock(BlockBegin block) {
-        if (block.checkBlockFlag(BlockBegin.BlockFlag.BackwardBranchTarget)) {
-            emitAlignment();
-        }
 
         block.setBlockEntryPco(codePos());
 
@@ -256,18 +253,6 @@
         switch (op.code) {
             case Label:
                 throw Util.shouldNotReachHere();
-            case OsrEntry:
-                emitOsrEntry();
-                break;
-            case Here:
-                emitHere(op.result(), op.info, false);
-                break;
-            case Info:
-                emitHere(op.result(), op.info, true);
-                break;
-            case Pause:
-                emitPause();
-                break;
             case Breakpoint:
                 emitBreakpoint();
                 break;
@@ -412,12 +397,8 @@
 
     protected abstract void emitNegate(LIRNegate negate);
 
-    protected abstract void emitHere(CiValue dst, LIRDebugInfo info, boolean infoOnly);
-
     protected abstract void emitMonitorAddress(int monitor, CiValue dst);
 
-    protected abstract void emitPause();
-
     protected abstract void emitStackAllocate(StackBlock src, CiValue dst);
 
     protected abstract void emitReturn(CiValue inOpr);
@@ -470,8 +451,6 @@
 
     protected abstract void emitMemoryBarriers(int barriers);
 
-    protected abstract void emitOsrEntry();
-
     protected abstract void reg2stack(CiValue src, CiValue dest, CiKind kind);
 
     protected abstract void reg2mem(CiValue src, CiValue dest, CiKind kind, LIRDebugInfo info, boolean unaligned);
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRBlock.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIRBlock.java	Wed May 18 18:40:58 2011 +0200
@@ -32,6 +32,7 @@
 public final class LIRBlock {
 
     public LIRBlock() {
+        loopIndex = -1;
     }
 
     public final Label label = new Label();
@@ -66,10 +67,29 @@
      */
     public CiBitMap liveKill;
 
-    public int firstLirInstructionID;
-    public int lastLirInstructionID;
+    private int firstLirInstructionID;
+    private int lastLirInstructionID;
     public int blockEntryPco;
 
+    public int firstLirInstructionId() {
+        return firstLirInstructionID;
+    }
+
+    public void setFirstLirInstructionId(int firstLirInstructionId) {
+        this.firstLirInstructionID = firstLirInstructionId;
+    }
+
+    public int lastLirInstructionId() {
+        return lastLirInstructionID;
+    }
+
+    public void setLastLirInstructionId(int lastLirInstructionId) {
+        this.lastLirInstructionID = lastLirInstructionId;
+    }
+
+    public int loopDepth;
+    public int loopIndex;
+
     public LIRList lir() {
         return lir;
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRList.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIRList.java	Wed May 18 18:40:58 2011 +0200
@@ -31,7 +31,6 @@
 import com.sun.c1x.gen.*;
 import com.sun.c1x.globalstub.*;
 import com.sun.c1x.ir.*;
-import com.sun.c1x.lir.FrameMap.StackBlock;
 import com.sun.cri.ci.*;
 import com.sun.cri.ci.CiTargetMethod.Mark;
 import com.sun.cri.ri.*;
@@ -101,10 +100,6 @@
         append(new LIRMemoryBarrier(barriers));
     }
 
-    public void osrEntry(CiValue osrPointer) {
-        append(new LIROp0(LIROpcode.OsrEntry, osrPointer));
-    }
-
     public void branchDestination(Label lbl) {
         append(new LIRLabel(lbl));
     }
@@ -155,14 +150,6 @@
         append(new LIRMonitorAddress(dst, monitor));
     }
 
-    public void infopoint(LIROpcode opcode, CiValue dst, LIRDebugInfo info) {
-        append(new LIROp0(opcode, dst, info));
-    }
-
-    public void alloca(StackBlock stackBlock, CiValue dst) {
-        append(new LIRStackAllocate(dst, stackBlock));
-    }
-
     public void convert(int code, CiValue left, CiValue dst, GlobalStub globalStub) {
         LIRConvert op = new LIRConvert(code, left, dst);
         op.globalStub = globalStub;
@@ -303,10 +290,6 @@
         append(new LIRCall(runtimeCallOp, rtCall, result, arguments, info, null, false, null));
     }
 
-    public void pause() {
-        append(new LIROp0(LIROpcode.Pause));
-    }
-
     public void breakpoint() {
         append(new LIROp0(LIROpcode.Breakpoint));
     }
@@ -411,16 +394,10 @@
         TTY.print("B%d ", x.blockID);
 
         // print flags
-        if (x.checkBlockFlag(BlockBegin.BlockFlag.SubroutineEntry)) {
-            TTY.print("jsr ");
-        }
-        if (x.checkBlockFlag(BlockBegin.BlockFlag.BackwardBranchTarget)) {
-            TTY.print("bb ");
-        }
-        if (x.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader)) {
+        if (x.isLinearScanLoopHeader()) {
             TTY.print("lh ");
         }
-        if (x.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd)) {
+        if (x.isLinearScanLoopEnd()) {
             TTY.print("le ");
         }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIROpcode.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIROpcode.java	Wed May 18 18:40:58 2011 +0200
@@ -33,12 +33,7 @@
     // @formatter:off
     BeginOp0,
         Label,
-        OsrEntry,
-        Here,
-        Info,
-        Alloca,
         Breakpoint,
-        Pause,
         RuntimeCall,
         Membar,
         Branch,
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRStackAllocate.java	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2010, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.sun.c1x.lir;
-
-import com.sun.c1x.lir.FrameMap.*;
-import com.sun.cri.bytecode.*;
-import com.sun.cri.ci.*;
-
-/**
- * LIR instruction used in translating {@link Bytecodes#ALLOCA}.
- *
- * @author Doug Simon
- */
-public class LIRStackAllocate extends LIRInstruction {
-
-    public final StackBlock stackBlock;
-
-    /**
-     * Creates an LIR instruction modelling a stack block allocation.
-     * @param result
-     */
-    public LIRStackAllocate(CiValue result, StackBlock stackBlock) {
-        super(LIROpcode.Alloca, result, null, false);
-        this.stackBlock = stackBlock;
-    }
-
-    @Override
-    public void emitCode(LIRAssembler masm) {
-        masm.emitStackAllocate(stackBlock, this.result());
-    }
-}
--- a/graal/GraalCompiler/src/com/sun/c1x/opt/InstructionSubstituter.java	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.sun.c1x.opt;
-
-import com.sun.c1x.ir.*;
-import com.sun.c1x.value.*;
-import com.sun.c1x.graph.IR;
-
-/**
- * This class allows instructions to be substituted within an IR graph. It allows
- * registering substitutions and iterates over the instructions of a program and replaces
- * the occurrence of each instruction with its substitution, if it has one.
- */
-public final class InstructionSubstituter implements BlockClosure, ValueClosure {
-
-    final IR ir;
-    boolean hasSubstitution;
-
-    public InstructionSubstituter(IR ir) {
-        this.ir = ir;
-    }
-
-    public void apply(BlockBegin block) {
-        Instruction last = null;
-        for (Instruction n = block; n != null; n = last.next()) {
-            n.allValuesDo(this);
-            if (n.subst != null && last != null) {
-                // this instruction has a substitution, skip it
-                last.resetNext(n.next());
-            } else {
-                last = n;
-            }
-        }
-    }
-
-    public void finish() {
-        if (hasSubstitution) {
-            ir.startBlock.iterateAnyOrder(this, false);
-        }
-    }
-
-    public boolean hasSubst(Value i) {
-        return i.subst != null;
-    }
-
-    public void setSubst(Value i, Value n) {
-        if (i == n) {
-            i.subst = null;
-        } else {
-            hasSubstitution = true;
-            i.subst = n;
-        }
-    }
-
-    public Value getSubst(Value i) {
-        Value p = i;
-        while (true) {
-            if (p.subst == null) {
-                break;
-            }
-            p = p.subst;
-        }
-        return p;
-    }
-
-    public Value apply(Value i) {
-        if (i instanceof FrameState) {
-            FrameState state = (FrameState) i;
-            state.inputValuesDo(this);
-        }
-        if (i != null) {
-            return getSubst(i);
-        }
-        return i;
-    }
-}
--- a/graal/GraalCompiler/src/com/sun/c1x/opt/PhiSimplifier.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/opt/PhiSimplifier.java	Wed May 18 18:40:58 2011 +0200
@@ -34,13 +34,10 @@
 public final class PhiSimplifier implements BlockClosure {
 
     final IR ir;
-    final InstructionSubstituter subst;
 
     public PhiSimplifier(IR ir) {
         this.ir = ir;
-        this.subst = new InstructionSubstituter(ir);
         ir.startBlock.iterateAnyOrder(this, false);
-        subst.finish();
     }
 
     /**
@@ -62,10 +59,7 @@
             return x;
         }
         Phi phi = (Phi) x;
-        if (phi.hasSubst()) {
-            // already substituted, but the subst could be a phi itself, so simplify
-            return simplify(subst.getSubst(phi));
-        } else if (phi.checkFlag(Value.Flag.PhiCannotSimplify)) {
+        if (phi.checkFlag(Value.Flag.PhiCannotSimplify)) {
             // already tried, cannot simplify this phi
             return phi;
         } else if (phi.checkFlag(Value.Flag.PhiVisited)) {
@@ -121,7 +115,6 @@
             // successfully simplified the phi
             assert phiSubst != null : "illegal phi function";
             phi.clearFlag(Value.Flag.PhiVisited);
-            subst.setSubst(phi, phiSubst);
             return phiSubst;
         }
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRAssembler.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRAssembler.java	Wed May 18 18:40:58 2011 +0200
@@ -81,11 +81,6 @@
     }
 
     @Override
-    protected void emitOsrEntry() {
-        throw Util.unimplemented();
-    }
-
-    @Override
     protected int initialFrameSizeInBytes() {
         return frameMap.frameSize();
     }
@@ -97,26 +92,12 @@
     }
 
     @Override
-    protected void emitHere(CiValue dst, LIRDebugInfo info, boolean infoOnly) {
-        tasm.recordSafepoint(codePos(), info);
-        if (!infoOnly) {
-            masm.codeBuffer.putMark();
-            masm.leaq(dst.asRegister(), new CiAddress(CiKind.Word, InstructionRelative.asValue(), 0));
-        }
-    }
-
-    @Override
     protected void emitMonitorAddress(int monitor, CiValue dst) {
         CiStackSlot slot = frameMap.toMonitorBaseStackAddress(monitor);
         masm.leaq(dst.asRegister(), new CiAddress(slot.kind, AMD64.rsp.asValue(), slot.index() * target.arch.wordSize));
     }
 
     @Override
-    protected void emitPause() {
-        masm.pause();
-    }
-
-    @Override
     protected void emitBreakpoint() {
         masm.int3();
     }
@@ -1336,7 +1317,7 @@
             } else if (left.kind.isDouble()) {
                 masm.cmpsd2int(asXmmDoubleReg(left), asXmmDoubleReg(right), dst.asRegister(), code == LIROpcode.Ucmpfd2i);
             } else {
-                throw Util.unimplemented("no fpu stack");
+                assert false : "no fpu stack";
             }
         } else {
             assert code == LIROpcode.Cmpl2i;
@@ -2062,7 +2043,7 @@
                     break;
                 }
                 default:
-                    throw Util.unimplemented("XIR operation " + inst.op);
+                    assert false : "Unknown XIR operation " + inst.op;
             }
         }
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java	Wed May 18 18:40:58 2011 +0200
@@ -440,7 +440,7 @@
             CiValue reg = createResultVariable(x);
             lir.lcmp2int(left.result(), right.result(), reg);
         } else {
-            Util.unimplemented();
+            assert false;
         }
     }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64XirAssembler.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64XirAssembler.java	Wed May 18 18:40:58 2011 +0200
@@ -27,7 +27,6 @@
 import java.util.*;
 
 import com.oracle.max.asm.target.amd64.*;
-import com.sun.c1x.util.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.xir.*;
 
@@ -194,7 +193,7 @@
                 case ShouldNotReachHere:
                     break;
                 default:
-                    throw Util.unimplemented("XIR operation " + i.op);
+                    assert false : "Unknown XIR operation " + i.op;
             }
             if (!appended) {
                 currentList.add(i);
--- a/graal/GraalCompiler/src/com/sun/c1x/target/sparc/SPARC.java	Wed May 18 18:09:20 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.sun.c1x.target.sparc;
-
-import static com.sun.cri.bytecode.Bytecodes.MemoryBarriers.*;
-import static com.sun.cri.ci.CiRegister.RegisterFlag.*;
-
-import com.sun.cri.ci.*;
-
-/**
- * Represents the SPARC architecture.
- *
- * @author Thomas Wuerthinger
- */
-public class SPARC extends CiArchitecture {
-
-    // General purpose CPU registers
-    public static final CiRegister g0 = new CiRegister(0,  0,  8, "g0", CPU);
-    public static final CiRegister g1 = new CiRegister(1,  1,  8, "g1", CPU);
-    public static final CiRegister g2 = new CiRegister(2,  2,  8, "g2", CPU);
-    public static final CiRegister g3 = new CiRegister(3,  3,  8, "g3", CPU);
-    public static final CiRegister g4 = new CiRegister(4,  4,  8, "g4", CPU);
-    public static final CiRegister g5 = new CiRegister(5,  5,  8, "g5", CPU);
-    public static final CiRegister g6 = new CiRegister(6,  6,  8, "g6", CPU);
-    public static final CiRegister g7 = new CiRegister(7,  7,  8, "g7", CPU);
-
-    public static final CiRegister o0 = new CiRegister(8,  8,  8, "o0", CPU);
-    public static final CiRegister o1 = new CiRegister(9,  9,  8, "o1", CPU);
-    public static final CiRegister o2 = new CiRegister(10, 10, 8, "o2", CPU);
-    public static final CiRegister o3 = new CiRegister(11, 11, 8, "o3", CPU);
-    public static final CiRegister o4 = new CiRegister(12, 12, 8, "o4", CPU);
-    public static final CiRegister o5 = new CiRegister(13, 13, 8, "o5", CPU);
-    public static final CiRegister o6 = new CiRegister(14, 14, 8, "o6", CPU);
-    public static final CiRegister o7 = new CiRegister(15, 15, 8, "o7", CPU);
-
-    public static final CiRegister l0 = new CiRegister(16, 16, 8, "l0", CPU);
-    public static final CiRegister l1 = new CiRegister(17, 17, 8, "l1", CPU);
-    public static final CiRegister l2 = new CiRegister(18, 18, 8, "l2", CPU);
-    public static final CiRegister l3 = new CiRegister(19, 19, 8, "l3", CPU);
-    public static final CiRegister l4 = new CiRegister(20, 20, 8, "l4", CPU);
-    public static final CiRegister l5 = new CiRegister(21, 21, 8, "l5", CPU);
-    public static final CiRegister l6 = new CiRegister(22, 22, 8, "l6", CPU);
-    public static final CiRegister l7 = new CiRegister(23, 23, 8, "l7", CPU);
-
-    public static final CiRegister i0 = new CiRegister(24, 24, 8, "i0", CPU);
-    public static final CiRegister i1 = new CiRegister(25, 25, 8, "i1", CPU);
-    public static final CiRegister i2 = new CiRegister(26, 26, 8, "i2", CPU);
-    public static final CiRegister i3 = new CiRegister(27, 27, 8, "i3", CPU);
-    public static final CiRegister i4 = new CiRegister(28, 28, 8, "i4", CPU);
-    public static final CiRegister i5 = new CiRegister(29, 29, 8, "i5", CPU);
-    public static final CiRegister i6 = new CiRegister(30, 30, 8, "i6", CPU);
-    public static final CiRegister i7 = new CiRegister(31, 31, 8, "i7", CPU);
-
-    public static final CiRegister[] cpuRegisters = {
-        g0, g1, g2, g3, g4, g5, g6, g7,
-        o0, o1, o2, o3, o4, o5, o6, o7,
-        l0, l1, l2, l3, l4, l5, l6, l7,
-        i0, i1, i2, i3, i4, i5, i6, i7
-    };
-
-    protected SPARC(int wordSize, CiRegister[] registers) {
-        super("SPARC",
-              wordSize,
-              ByteOrder.BigEndian,
-              registers,
-              LOAD_LOAD | LOAD_STORE | STORE_STORE,
-              0,
-              i7.encoding + 1,
-              0);
-    }
-
-    @Override
-    public boolean isSPARC() {
-        return true;
-    }
-
-}
--- a/graal/GraalCompiler/src/com/sun/c1x/value/ValueUtil.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/ValueUtil.java	Wed May 18 18:40:58 2011 +0200
@@ -23,6 +23,7 @@
 package com.sun.c1x.value;
 
 import com.sun.c1x.ir.*;
+import com.sun.c1x.util.*;
 import com.sun.cri.ci.*;
 
 
@@ -73,7 +74,7 @@
     }
 
     public static boolean typeMismatch(Value x, Value y) {
-        return y == null || x.kind != y.kind;
+        return y == null || !Util.archKindsEqual(x, y);
     }
 
     public static boolean isDoubleWord(Value x) {
--- a/graal/GraalRuntime/.classpath	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalRuntime/.classpath	Wed May 18 18:40:58 2011 +0200
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/Assembler"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/Base"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/CRI"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/GraalCompiler"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/com.oracle.max.asm"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/GraalCompiler"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/com.oracle.max.asm"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/com.oracle.max.base"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/com.oracle.max.asmdis"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/com.oracle.max.cri"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
--- a/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotMethodResolved.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotMethodResolved.java	Wed May 18 18:40:58 2011 +0200
@@ -152,7 +152,6 @@
         return CiUtil.toStackTraceElement(this, bci);
     }
 
-    @Override
     public RiMethod uniqueConcreteMethod() {
         return compiler.getVMEntries().RiMethod_uniqueConcreteMethod(vmId);
     }
--- a/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotMethodUnresolved.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotMethodUnresolved.java	Wed May 18 18:40:58 2011 +0200
@@ -79,11 +79,6 @@
     }
 
     @Override
-    public RiMethod uniqueConcreteMethod() {
-        throw unresolved("uniqueConcreteMethod()");
-    }
-
-    @Override
     public int accessFlags() {
         throw unresolved("accessFlags");
     }
--- a/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotTypePrimitive.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotTypePrimitive.java	Wed May 18 18:40:58 2011 +0200
@@ -150,4 +150,9 @@
         return this;
     }
 
+    @Override
+    public RiMethod uniqueConcreteMethod(RiMethod method) {
+        return null;
+    }
+
 }
--- a/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotTypeResolvedImpl.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotTypeResolvedImpl.java	Wed May 18 18:40:58 2011 +0200
@@ -222,4 +222,10 @@
         return result;
     }
 
+    @Override
+    public RiMethod uniqueConcreteMethod(RiMethod method) {
+        assert method instanceof HotSpotMethodResolved;
+        return ((HotSpotMethodResolved) method).uniqueConcreteMethod();
+    }
+
 }
--- a/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotTypeUnresolved.java	Wed May 18 18:09:20 2011 +0200
+++ b/graal/GraalRuntime/src/com/oracle/graal/runtime/HotSpotTypeUnresolved.java	Wed May 18 18:40:58 2011 +0200
@@ -201,4 +201,9 @@
         return CiKind.Object;
     }
 
+    @Override
+    public RiMethod uniqueConcreteMethod(RiMethod method) {
+        throw unresolved("uniqueConcreteMethod");
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/hotspot/hotspot Default.launch	Wed May 18 18:40:58 2011 +0200
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.cdt.launch.applicationLaunchType">
+<booleanAttribute key="org.eclipse.cdt.dsf.gdb.AUTO_SOLIB" value="true"/>
+<listAttribute key="org.eclipse.cdt.dsf.gdb.AUTO_SOLIB_LIST"/>
+<stringAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_NAME" value="gdb"/>
+<stringAttribute key="org.eclipse.cdt.dsf.gdb.GDB_INIT" value=".gdbinit"/>
+<booleanAttribute key="org.eclipse.cdt.dsf.gdb.NON_STOP" value="false"/>
+<booleanAttribute key="org.eclipse.cdt.dsf.gdb.REVERSE" value="false"/>
+<listAttribute key="org.eclipse.cdt.dsf.gdb.SOLIB_PATH"/>
+<booleanAttribute key="org.eclipse.cdt.dsf.gdb.UPDATE_THREADLIST_ON_SUSPEND" value="false"/>
+<booleanAttribute key="org.eclipse.cdt.dsf.gdb.internal.ui.launching.LocalApplicationCDebuggerTab.DEFAULTS_SET" value="true"/>
+<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="2"/>
+<stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
+<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_ID" value="gdb"/>
+<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_START_MODE" value="run"/>
+<booleanAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN" value="true"/>
+<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_STOP_AT_MAIN_SYMBOL" value="main"/>
+<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_ARGUMENTS" value="-client -XX:+UseC1X -XX:+PrintGC -Xms1g -Xmx1g -Xbootclasspath/p:${workspace_loc:hotspot}/../../../maxine/C1X/bin:${workspace_loc:hotspot}/../../../maxine/com.oracle.max.cri/bin:${workspace_loc:hotspot}/../../../maxine/com.oracle.max.base/bin:${workspace_loc:hotspot}/../../../maxine/com.oracle.max.asmdis/bin:${workspace_loc:hotspot}/../HotSpotVM/bin -classpath ${workspace_loc:hotspot}/../HotSpotTest/bin C1XTest"/>
+<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="java"/>
+<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="hotspot"/>
+<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="cdt.managedbuild.toolchain.gnu.solaris.base.945602881"/>
+<booleanAttribute key="org.eclipse.cdt.launch.use_terminal" value="true"/>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/hotspot"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;memoryBlockExpressionList context=&quot;reserved-for-future-use&quot;/&gt;&#10;"/>
+</launchConfiguration>
--- a/runtests.sh	Wed May 18 18:09:20 2011 +0200
+++ b/runtests.sh	Wed May 18 18:40:58 2011 +0200
@@ -11,4 +11,5 @@
   echo "GRAAL is not defined. It must point to a maxine repository directory."
   exit 1;
 fi
-${JDK7}/bin/java -client -d64 -graal -ea -esa -Xcomp -XX:+PrintCompilation -XX:CompileOnly=jtt -Xbootclasspath/p:"${MAXINE}/VM/bin" -Xbootclasspath/p:"${MAXINE}/Base/bin" $1 test.com.sun.max.vm.compiler.JavaTester -verbose=1 -gen-run-scheme=false -run-scheme-package=all ${MAXINE}/VM/test/jtt/bytecode ${MAXINE}/VM/test/jtt/except ${MAXINE}/VM/test/jtt/hotpath ${MAXINE}/VM/test/jtt/jdk ${MAXINE}/VM/test/jtt/lang ${MAXINE}/VM/test/jtt/loop ${MAXINE}/VM/test/jtt/micro ${MAXINE}/VM/test/jtt/optimize ${MAXINE}/VM/test/jtt/reflect ${MAXINE}/VM/test/jtt/threads
+TESTDIR=${MAXINE}/com.oracle.max.vm/test
+${JDK7}/bin/java -client -d64 -graal -ea -esa -Xcomp -XX:+PrintCompilation -XX:CompileOnly=jtt -Xbootclasspath/p:"${MAXINE}/com.oracle.max.vm/bin" -Xbootclasspath/p:"${MAXINE}/com.oracle.max.base/bin" $1 test.com.sun.max.vm.compiler.JavaTester -verbose=1 -gen-run-scheme=false -run-scheme-package=all ${TESTDIR}/jtt/bytecode ${TESTDIR}/jtt/except ${TESTDIR}/jtt/hotpath ${TESTDIR}/jtt/jdk ${TESTDIR}/jtt/lang ${TESTDIR}/jtt/loop ${TESTDIR}/jtt/micro ${TESTDIR}/jtt/optimize ${TESTDIR}/jtt/reflect ${TESTDIR}/jtt/threads
--- a/src/share/vm/runtime/arguments.cpp	Wed May 18 18:09:20 2011 +0200
+++ b/src/share/vm/runtime/arguments.cpp	Wed May 18 18:40:58 2011 +0200
@@ -2682,11 +2682,11 @@
         fatal("Must set GRAAL environment variable to a Graal project directory.");
       }
       if (PrintVMOptions) tty->print_cr(" GRAAL=%s", graal_dir);
-      sprintf(temp, "%s/CRI/bin", maxine_dir);
+      sprintf(temp, "%s/com.oracle.max.cri/bin", maxine_dir);
       scp_p->add_prefix(temp);
-      sprintf(temp, "%s/Base/bin", maxine_dir);
+      sprintf(temp, "%s/com.oracle.max.base/bin", maxine_dir);
       scp_p->add_prefix(temp);
-      sprintf(temp, "%s/Assembler/bin", maxine_dir);
+      sprintf(temp, "%s/com.oracle.max.asmdis/bin", maxine_dir);
       scp_p->add_prefix(temp);
       sprintf(temp, "%s/com.oracle.max.asm/bin", maxine_dir);
       scp_p->add_prefix(temp);