changeset 2674:6ab73784566a

* BlockBegin.predecessors changed to List<BlockEnd> * Node: add input/successor with given back edge index, allows for explicit ordering of predecessors/usages * Graphviz: PDF output, option to omit FrameStates * runscimark.sh: forward additional options to JVM
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 13 May 2011 15:18:41 +0200
parents 98447ab8bd83
children e0e89714e2f1
files .hgignore graal/GraalCompiler/bin/com/sun/c1x/doc/IRInterpreter.txt graal/GraalCompiler/bin/com/sun/c1x/doc/LoopPeeling.txt graal/GraalCompiler/bin/com/sun/c1x/doc/backend_open_issues.txt graal/GraalCompiler/bin/com/sun/c1x/doc/differences.txt graal/GraalCompiler/bin/com/sun/c1x/doc/performance.txt graal/GraalCompiler/src/com/sun/c1x/C1XCompiler.java graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java graal/GraalCompiler/src/com/sun/c1x/alloc/ControlFlowOptimizer.java graal/GraalCompiler/src/com/sun/c1x/alloc/EdgeMoveOptimizer.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/debug/GraphvizPrinterObserver.java graal/GraalCompiler/src/com/sun/c1x/graph/BlockUtil.java graal/GraalCompiler/src/com/sun/c1x/graph/CriticalEdgeFinder.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/BlockEnd.java graal/GraalCompiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java graal/GraalCompiler/src/com/sun/c1x/lir/LIRList.java graal/GraalGraph/src/com/oracle/graal/graph/Node.java graal/GraalGraph/src/com/oracle/graal/graph/NodeArray.java graal/GraalGraphviz/src/com/oracle/graal/graph/vis/GraphvizPrinter.java runscimark.sh src/share/vm/c1x/c1x_Compiler.cpp
diffstat 27 files changed, 334 insertions(+), 511 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri May 13 11:19:25 2011 +0200
+++ b/.hgignore	Fri May 13 15:18:41 2011 +0200
@@ -16,6 +16,7 @@
 output\.txt$
 output\.cfg$
 /nbproject/private/
+^graal/hotspot/java$
 ^scratch/
 ^src/share/tools/hsdis/build/
 ^src/share/tools/IdealGraphVisualizer/[a-zA-Z0-9]*/build/
--- a/graal/GraalCompiler/bin/com/sun/c1x/doc/IRInterpreter.txt	Fri May 13 11:19:25 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/bin/com/sun/c1x/doc/LoopPeeling.txt	Fri May 13 11:19:25 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/bin/com/sun/c1x/doc/backend_open_issues.txt	Fri May 13 11:19:25 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/bin/com/sun/c1x/doc/differences.txt	Fri May 13 11:19:25 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/bin/com/sun/c1x/doc/performance.txt	Fri May 13 11:19:25 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/C1XCompiler.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XCompiler.java	Fri May 13 15:18:41 2011 +0200
@@ -126,7 +126,10 @@
             addCompilationObserver(new CFGPrinterObserver());
         }
         if (C1XOptions.PrintDOTGraphToFile) {
-            addCompilationObserver(new GraphvizPrinterObserver());
+            addCompilationObserver(new GraphvizPrinterObserver(false));
+        }
+        if (C1XOptions.PrintDOTGraphToPdf) {
+            addCompilationObserver(new GraphvizPrinterObserver(true));
         }
     }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java	Fri May 13 15:18:41 2011 +0200
@@ -68,6 +68,8 @@
     public static boolean PrintLIR                           = ____;
     public static boolean PrintCFGToFile                     = ____;
     public static boolean PrintDOTGraphToFile                = ____;
+    public static boolean PrintDOTGraphToPdf                 = ____;
+    public static boolean OmitDOTFrameStates                 = true;
     public static boolean PrintMetrics                       = ____;
     public static boolean PrintTimers                        = ____;
     public static boolean PrintCompilation                   = ____;
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/ControlFlowOptimizer.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/ControlFlowOptimizer.java	Fri May 13 15:18:41 2011 +0200
@@ -138,8 +138,8 @@
                 }
 
                 // update the block references in any branching LIR instructions
-                for (BlockBegin pred : block.blockPredecessors()) {
-                    for (LIRInstruction instr : pred.lir().instructionsList()) {
+                for (BlockEnd pred : block.blockPredecessors()) {
+                    for (LIRInstruction instr : pred.begin().lir().instructionsList()) {
                         if (instr instanceof LIRBranch) {
                             ((LIRBranch) instr).substitute(block, newTarget);
                         } else if (instr instanceof LIRTableSwitch) {
@@ -228,7 +228,7 @@
                 CiValue returnOpr = ((LIROp1) curLastOp).operand();
 
                 for (int j = block.numberOfPreds() - 1; j >= 0; j--) {
-                    BlockBegin pred = block.predAt(j);
+                    BlockBegin pred = block.predAt(j).begin();
                     List<LIRInstruction> predInstructions = pred.lir().instructionsList();
                     LIRInstruction predLastOp = predInstructions.get(predInstructions.size() - 1);
 
@@ -263,8 +263,8 @@
                 assert code.contains(sux) : "missing successor from: " + block + "to: " + sux;
             }
 
-            for (BlockBegin pred : block.blockPredecessors()) {
-                assert code.contains(pred) : "missing predecessor from: " + block + "to: " + pred;
+            for (BlockEnd pred : block.blockPredecessors()) {
+                assert code.contains(pred.begin()) : "missing predecessor from: " + block + "to: " + pred.begin();
             }
         }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/EdgeMoveOptimizer.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/EdgeMoveOptimizer.java	Fri May 13 15:18:41 2011 +0200
@@ -112,7 +112,7 @@
      * predecessors of {@code block} to the start of {@code block}.
      */
     private void optimizeMovesAtBlockEnd(BlockBegin block) {
-        if (block.isPredecessor(block)) {
+        if (block.isPredecessor(block.end())) {
             // currently we can't handle this correctly.
             return;
         }
@@ -126,7 +126,7 @@
 
         // setup a list with the LIR instructions of all predecessors
         for (int i = 0; i < numPreds; i++) {
-            BlockBegin pred = block.predAt(i);
+            BlockBegin pred = block.predAt(i).begin();
             List<LIRInstruction> predInstructions = pred.lir().instructionsList();
 
             if (pred.numberOfSux() != 1) {
@@ -231,7 +231,7 @@
                 // the same blocks.
                 return;
             }
-            assert sux.predAt(0) == block : "invalid control flow";
+            assert sux.predAt(0).begin() == block : "invalid control flow";
             assert !sux.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry) : "exception handlers not allowed";
 
             // ignore the label at the beginning of the block
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Fri May 13 15:18:41 2011 +0200
@@ -1596,7 +1596,7 @@
                 // may have be more than one predecessor but it will be guaranteed
                 // that all predecessors will be the same.
                 for (int i = 0; i < toBlock.numberOfPreds(); i++) {
-                    assert fromBlock == toBlock.predAt(i) : "all critical edges must be broken";
+                    assert fromBlock == toBlock.predAt(i).begin() : "all critical edges must be broken";
                 }
             }
 
@@ -1627,7 +1627,7 @@
 
                 // check if block is empty (only label and branch)
                 if (instructions.size() == 2) {
-                    BlockBegin pred = block.predAt(0);
+                    BlockBegin pred = block.predAt(0).begin();
                     BlockBegin sux = block.suxAt(0);
 
                     // prevent optimization of two consecutive blocks
--- a/graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java	Fri May 13 15:18:41 2011 +0200
@@ -132,8 +132,8 @@
         out.print("to_bci ").println(block.end() == null ? -1 : block.end().bci());
 
         out.print("predecessors ");
-        for (BlockBegin pred : block.blockPredecessors()) {
-            out.print("\"B").print(pred.blockID).print("\" ");
+        for (BlockEnd pred : block.blockPredecessors()) {
+            out.print("\"B").print(pred.begin().blockID).print("\" ");
         }
         out.println();
 
--- a/graal/GraalCompiler/src/com/sun/c1x/debug/GraphvizPrinterObserver.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/debug/GraphvizPrinterObserver.java	Fri May 13 15:18:41 2011 +0200
@@ -26,7 +26,9 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.vis.*;
+import com.sun.c1x.*;
 import com.sun.c1x.observer.*;
+import com.sun.c1x.value.*;
 
 /**
  * Observes compilation events and uses {@link GraphvizPrinter} to produce a control flow graph in the DOT language
@@ -36,9 +38,11 @@
  */
 public class GraphvizPrinterObserver implements CompilationObserver {
 
+    private final boolean pdf;
     private int n;
 
-    public GraphvizPrinterObserver() {
+    public GraphvizPrinterObserver(boolean pdf) {
+        this.pdf = pdf;
     }
 
     public void compilationStarted(CompilationEvent event) {
@@ -55,16 +59,34 @@
             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();
             try {
-                FileOutputStream stream = new FileOutputStream(name + "_" + n + "_" + event.getLabel() + ".gv");
-                n++;
+                if (pdf) {
+                    ByteArrayOutputStream out = new ByteArrayOutputStream();
+                    GraphvizPrinter printer = new GraphvizPrinter(out);
+                    if (C1XOptions.OmitDOTFrameStates) {
+                        printer.addOmittedClass(FrameState.class);
+                    }
+                    printer.begin(name);
+                    printer.print(graph, true);
+                    printer.end();
 
-                GraphvizPrinter printer = new GraphvizPrinter(stream);
-                printer.begin(name);
-                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();
+                } else {
+                    final FileOutputStream stream = new FileOutputStream(filename + ".gv");
 
-                stream.close();
+                    GraphvizPrinter printer = new GraphvizPrinter(stream);
+                    if (C1XOptions.OmitDOTFrameStates) {
+                        printer.addOmittedClass(FrameState.class);
+                    }
+                    printer.begin(name);
+                    printer.print(graph, true);
+                    printer.end();
+
+                    stream.close();
+                }
             } catch (IOException e) {
                 e.printStackTrace();
             }
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/BlockUtil.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/BlockUtil.java	Fri May 13 15:18:41 2011 +0200
@@ -36,8 +36,8 @@
      * @param block the block to remove from the graph
      */
     public static void disconnectFromGraph(BlockBegin block) {
-        for (BlockBegin p : block.blockPredecessors()) {
-            p.end().blockSuccessors().remove(block);
+        for (BlockEnd p : block.blockPredecessors()) {
+            p.blockSuccessors().remove(block);
         }
         for (BlockBegin s : block.end().blockSuccessors()) {
             s.blockPredecessors().remove(block);
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/CriticalEdgeFinder.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/CriticalEdgeFinder.java	Fri May 13 15:18:41 2011 +0200
@@ -70,8 +70,9 @@
     }
 
     public void splitCriticalEdges() {
-        for (BlockBegin from : edges.keySet()) {
-            for (BlockBegin to : edges.get(from)) {
+        for (Map.Entry<BlockBegin, Set<BlockBegin>> entry : edges.entrySet()) {
+            BlockBegin from = entry.getKey();
+            for (BlockBegin to : entry.getValue()) {
                 BlockBegin split = ir.splitEdge(from, to);
                 if (C1XOptions.PrintHIR) {
                     TTY.println("Split edge between block %d and block %d, creating new block %d", from.blockID, to.blockID, split.blockID);
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Fri May 13 15:18:41 2011 +0200
@@ -111,6 +111,8 @@
 
     private final Graph graph;
 
+    private final List<BlockBegin> newExceptionHandlers = new ArrayList<BlockBegin>();
+
     /**
      * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation.
      *
@@ -148,7 +150,7 @@
         // 1. create the start block
         ir.startBlock = new BlockBegin(0, ir.nextBlockNumber(), graph);
         BlockBegin startBlock = ir.startBlock;
-        graph.root().setStart(startBlock);
+//        graph.root().setStart(startBlock);
 
         // 2. compute the block map, setup exception handlers and get the entrypoint(s)
         blockMap = compilation.getBlockMap(rootMethod);
@@ -298,10 +300,7 @@
         // add entry to the list of exception handlers of this block
         curBlock.addExceptionHandler(entry);
 
-        // add back-edge from exception handler entry to this block
-        if (!entry.blockPredecessors().contains(curBlock)) {
-            entry.addPredecessor(curBlock);
-        }
+        newExceptionHandlers.add(entry);
 
         // clone exception handler
         ExceptionHandler newHandler = new ExceptionHandler(handler);
@@ -504,7 +503,12 @@
         BlockBegin fsucc = blockAt(stream().nextBCI());
         int bci = stream().currentBCI();
         boolean isSafepoint = !noSafepoints() && (tsucc.bci() <= bci || fsucc.bci() <= bci);
-        append(new If(x, cond, y, tsucc, fsucc, isSafepoint ? stateBefore : null, isSafepoint, graph));
+        if (isSafepoint) {
+            append(new If(x, cond, y, tsucc, fsucc, stateBefore, isSafepoint, graph));
+        } else {
+            append(new If(x, cond, y, tsucc, fsucc, null, isSafepoint, graph));
+            stateBefore.delete();
+        }
     }
 
     private void genIfZero(Condition cond) {
@@ -539,15 +543,9 @@
         int cpi = stream().readCPI();
         RiType type = constantPool().lookupType(cpi, CHECKCAST);
         boolean isInitialized = type.isResolved();
-        Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi, frameState.create(bci()));
-        Instruction result;
-        Value object = frameState.apop();
-        if (typeInstruction != null) {
-            result = new CheckCast(type, typeInstruction, object, graph);
-        } else {
-            result = Constant.forObject(null, graph);
-        }
-        frameState.apush(append(result));
+        Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi, frameState);
+        CheckCast c = new CheckCast(type, typeInstruction, frameState.apop(), graph);
+        frameState.apush(append(c));
     }
 
     private void genInstanceOf() {
@@ -555,7 +553,7 @@
         RiType type = constantPool().lookupType(cpi, INSTANCEOF);
         boolean isInitialized = type.isResolved();
         //System.out.println("instanceof : type.isResolved() = " + type.isResolved() + "; type.isInitialized() = " + type.isInitialized());
-        Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi, frameState.create(bci()));
+        Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi, frameState);
         Instruction result;
         Value object = frameState.apop();
         if (typeInstruction != null) {
@@ -637,14 +635,14 @@
         RiType holder = field.holder();
         boolean isInitialized = field.isResolved();
         CiConstant constantValue = null;
-        FrameState stateBefore = frameState.create(bci());
         if (isInitialized) {
             constantValue = field.constantValue(null);
         }
         if (constantValue != null) {
             frameState.push(constantValue.kind.stackKind(), appendConstant(constantValue));
         } else {
-            Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi, stateBefore);
+            FrameState stateBefore = frameState.create(bci());
+            Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi, frameState);
             if (container == null) {
                 container = Constant.forObject(null, graph);
             }
@@ -656,7 +654,7 @@
     private void genPutStatic(int cpi, RiField field) {
         RiType holder = field.holder();
         FrameState stateBefore = frameState.create(bci());
-        Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, field.isResolved(), cpi, stateBefore);
+        Value container = genTypeOrDeopt(RiType.Representation.StaticFields, holder, field.isResolved(), cpi, frameState);
         Value value = frameState.pop(field.kind().stackKind());
         if (container != null) {
             StoreField store = new StoreField(container, field, value, graph);
@@ -667,11 +665,11 @@
         }
     }
 
-    private Value genTypeOrDeopt(RiType.Representation representation, RiType holder, boolean initialized, int cpi, FrameState stateBefore) {
+    private Value genTypeOrDeopt(RiType.Representation representation, RiType holder, boolean initialized, int cpi, FrameStateAccess stateBefore) {
         if (initialized) {
             return appendConstant(holder.getEncoding(representation));
         } else {
-            append(new Deoptimize(graph, stateBefore));
+            append(new Deoptimize(graph, stateBefore.duplicate(bci())));
             return null;
         }
     }
@@ -693,7 +691,7 @@
             // Re-use the same resolution code as for accessing a static field. Even though
             // the result of resolution is not used by the invocation (only the side effect
             // of initialization is required), it can be commoned with static field accesses.
-            genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi, frameState.create(bci()));
+            genTypeOrDeopt(RiType.Representation.StaticFields, holder, isInitialized, cpi, frameState);
         }
         Value[] args = frameState.popArguments(target.signature().argumentSlots(false));
         appendInvoke(INVOKESTATIC, target, args, cpi, constantPool);
@@ -1103,9 +1101,18 @@
         FrameState stateAtEnd = frameState.create(bci());
         end.setStateAfter(stateAtEnd);
         curBlock.setEnd(end);
+
+        for (BlockBegin entry : newExceptionHandlers) {
+            // add back-edge from exception handler entry to this block
+            if (!entry.blockPredecessors().contains(curBlock.end())) {
+                entry.addPredecessor(curBlock.end());
+            }
+        }
+        newExceptionHandlers.clear();
+
         // propagate the state
         for (BlockBegin succ : end.blockSuccessors()) {
-            assert succ.blockPredecessors().contains(curBlock);
+            assert succ.blockPredecessors().contains(curBlock.end());
             succ.mergeOrClone(stateAtEnd, method());
             addToWorkList(succ);
         }
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Fri May 13 15:18:41 2011 +0200
@@ -163,6 +163,8 @@
             bci = source.end().bci();
         }
 
+        int backEdgeIndex = target.predecessors().indexOf(source.end());
+
         // create new successor and mark it for special block order treatment
         BlockBegin newSucc = new BlockBegin(bci, nextBlockNumber(), compilation.graph);
 
@@ -172,6 +174,7 @@
         Goto e = new Goto(target, null, false, compilation.graph);
         newSucc.appendNext(e, bci);
         newSucc.setEnd(e);
+        e.reorderSuccessor(0, backEdgeIndex);
         // setup states
         FrameState s = source.end().stateAfter();
         newSucc.setStateBefore(s);
@@ -185,20 +188,20 @@
         // The ordering needs to be the same, so remove the link that the
         // set_end call above added and substitute the new_sux for this
         // block.
-        target.removePredecessor(newSucc);
+        target.removePredecessor(newSucc.end());
 
         // the successor could be the target of a switch so it might have
         // multiple copies of this predecessor, so substitute the new_sux
         // for the first and delete the rest.
-        List<BlockBegin> list = target.blockPredecessors();
-        int x = list.indexOf(source);
-        list.set(x, newSucc);
-        newSucc.addPredecessor(source);
-        Iterator<BlockBegin> iterator = list.iterator();
+        List<BlockEnd> list = target.blockPredecessors();
+        int x = list.indexOf(source.end());
+        list.set(x, newSucc.end());
+        newSucc.addPredecessor(source.end());
+        Iterator<BlockEnd> iterator = list.iterator();
         while (iterator.hasNext()) {
-            if (iterator.next() == source) {
+            if (iterator.next() == source.end()) {
                 iterator.remove();
-                newSucc.addPredecessor(source);
+                newSucc.addPredecessor(source.end());
             }
         }
         return newSucc;
@@ -207,17 +210,17 @@
     public void replaceBlock(BlockBegin oldBlock, BlockBegin newBlock) {
         assert !oldBlock.isExceptionEntry() : "cannot replace exception handler blocks (yet)";
         for (BlockBegin succ : oldBlock.end().blockSuccessors()) {
-            succ.removePredecessor(oldBlock);
+            succ.removePredecessor(oldBlock.end());
         }
-        for (BlockBegin pred : oldBlock.blockPredecessors()) {
+        for (BlockEnd pred : oldBlock.blockPredecessors()) {
             // substitute the new successor for this block in each predecessor
-            pred.end().substituteSuccessor(oldBlock, newBlock);
+            pred.substituteSuccessor(oldBlock, newBlock);
             // and add each predecessor to the successor
             newBlock.addPredecessor(pred);
         }
         // this block is now disconnected; remove all its incoming and outgoing edges
 //        oldBlock.blockPredecessors().clear();
-//        oldBlock.end().blockSuccessors().clear();
+//        oldBlock.end().successors().clear();
     }
 
     /**
@@ -225,8 +228,8 @@
      * @param block the block to remove from the graph
      */
     public void disconnectFromGraph(BlockBegin block) {
-        for (BlockBegin p : block.blockPredecessors()) {
-            p.end().blockSuccessors().remove(block);
+        for (BlockEnd p : block.blockPredecessors()) {
+            p.blockSuccessors().remove(block);
         }
         for (BlockBegin s : block.end().blockSuccessors()) {
             s.blockPredecessors().remove(block);
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java	Fri May 13 15:18:41 2011 +0200
@@ -76,12 +76,12 @@
             if (old != null) {
                 // disconnect this block from its current successors
                 for (BlockBegin s : old.blockSuccessors()) {
-                    s.blockPredecessors().remove(this);
+                    s.blockPredecessors().remove(this.end());
                 }
             }
             successors().set(super.successorCount() + SUCCESSOR_END, end);
             for (BlockBegin s : end.blockSuccessors()) {
-                s.addPredecessor(this);
+                s.addPredecessor(end);
             }
         }
     }
@@ -120,7 +120,7 @@
     /**
      * The {@link BlockBegin} nodes for which this node is a successor.
      */
-    private final List<BlockBegin> predecessors;
+    private final List<BlockEnd> predecessors;
 
     private int depthFirstNumber;
     private int linearScanNumber;
@@ -145,7 +145,7 @@
         this.blockID = blockID;
         depthFirstNumber = -1;
         linearScanNumber = -1;
-        predecessors = new ArrayList<BlockBegin>(2);
+        predecessors = new ArrayList<BlockEnd>(2);
         loopIndex = -1;
         setBCI(bci);
     }
@@ -154,8 +154,9 @@
      * Gets the list of predecessors of this block.
      * @return the predecessor list
      */
-    public List<BlockBegin> blockPredecessors() {
-        return predecessors;
+    public List<BlockEnd> blockPredecessors() {
+//      return Collections.unmodifiableList(predecessors);
+      return predecessors;
     }
 
     /**
@@ -289,7 +290,9 @@
             closure.apply(block);
             queueBlocks(queue, block.exceptionHandlerBlocks(), mark);
             queueBlocks(queue, block.end().blockSuccessors(), mark);
-            queueBlocks(queue, predecessors ? block.predecessors : null, mark);
+            if (predecessors) {
+                queueBlockEnds(queue, block.predecessors, mark);
+            }
         }
     }
 
@@ -304,6 +307,18 @@
         }
     }
 
+    private void queueBlockEnds(LinkedList<BlockBegin> queue, List<BlockEnd> list, IdentityHashMap<BlockBegin, BlockBegin> mark) {
+        if (list != null) {
+            for (BlockEnd end : list) {
+                BlockBegin b = end.begin();
+                if (!mark.containsKey(b)) {
+                    queue.offer(b);
+                    mark.put(b, b);
+                }
+            }
+        }
+    }
+
     private void iterate(IdentityHashMap<BlockBegin, BlockBegin> mark, BlockClosure closure) {
         if (!mark.containsKey(this)) {
             mark.put(this, this);
@@ -359,7 +374,8 @@
      * Add a predecessor to this block.
      * @param pred the predecessor to add
      */
-    public void addPredecessor(BlockBegin pred) {
+    public void addPredecessor(BlockEnd pred) {
+        assert pred != null;
         predecessors.add(pred);
     }
 
@@ -367,7 +383,7 @@
      * Removes all occurrences of the specified block from the predecessor list of this block.
      * @param pred the predecessor to remove
      */
-    public void removePredecessor(BlockBegin pred) {
+    public void removePredecessor(BlockEnd pred) {
         while (predecessors.remove(pred)) {
             // the block may appear multiple times in the list
             // XXX: this is not very efficient, consider Util.removeAllFromList
@@ -603,6 +619,7 @@
      * @return the number of predecessors
      */
     public int numberOfPreds() {
+//        assert predecessors.size() == predecessors().size();
         return predecessors.size();
     }
 
@@ -644,7 +661,8 @@
         return exceptionHandlerBlocks.get(i);
     }
 
-    public BlockBegin predAt(int j) {
+    public BlockEnd predAt(int j) {
+//        assert predecessors.get(j) == predecessors().get(j);
         return predecessors.get(j);
     }
 
@@ -664,8 +682,9 @@
         lirBlock.lastLirInstructionID = lastLirInstructionId;
     }
 
-    public boolean isPredecessor(BlockBegin block) {
-        return this.predecessors.contains(block);
+    public boolean isPredecessor(BlockEnd block) {
+//        assert predecessors.contains(block) == predecessors().contains(block);
+        return predecessors.contains(block);
     }
 
     public void printWithoutPhis(LogStream out) {
@@ -721,8 +740,8 @@
         // print predecessors
         if (!blockPredecessors().isEmpty()) {
             out.print(" pred:");
-            for (BlockBegin pred : blockPredecessors()) {
-                out.print(" B").print(pred.blockID);
+            for (BlockEnd pred : blockPredecessors()) {
+                out.print(" B").print(pred.begin().blockID);
             }
         }
     }
@@ -849,4 +868,11 @@
         }
         return sb.toString();
     }
+
+    @Override
+    public String shortName() {
+        return "BlockBegin #" + blockID;
+    }
+
+
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/BlockEnd.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/BlockEnd.java	Fri May 13 15:18:41 2011 +0200
@@ -166,6 +166,18 @@
     }
 
     /**
+     * This method reorders the predecessors of the i-th successor in such a way that this BlockEnd is at position backEdgeIndex.
+     */
+    public void reorderSuccessor(int i, int backEdgeIndex) {
+        assert i >= 0 && i < blockSuccessorCount;
+        BlockBegin successor = blockSuccessor(i);
+        if (successor != null) {
+            successors().set(super.successorCount() + SUCCESSOR_COUNT + i, Node.Null);
+            successors().set(super.successorCount() + SUCCESSOR_COUNT + i, successor, backEdgeIndex);
+        }
+    }
+
+    /**
      * Gets this block end's list of successors.
      * @return the successor list
      */
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java	Fri May 13 15:18:41 2011 +0200
@@ -250,7 +250,7 @@
                 // recursive processing of all predecessors ends when start block of loop is reached
                 if (cur != loopStart) {
                     for (int j = cur.numberOfPreds() - 1; j >= 0; j--) {
-                        BlockBegin pred = cur.predAt(j);
+                        BlockBegin pred = cur.predAt(j).begin();
 
                         if (!isBlockInLoop(loopIdx, pred)) {
                             // this predecessor has not been processed yet, so add it to work list
@@ -539,14 +539,14 @@
             BlockBegin block = linearScanOrder.get(i);
 
             assert block.numberOfPreds() > 0;
-            BlockBegin dominator = block.predAt(0);
+            BlockBegin dominator = block.predAt(0).begin();
             if (block.isExceptionEntry()) {
                 dominator = dominator.dominator();
             }
 
             int numPreds = block.numberOfPreds();
             for (int j = 1; j < numPreds; j++) {
-                BlockBegin curPred = block.predAt(j);
+                BlockBegin curPred = block.predAt(j).begin();
                 if (block.isExceptionEntry()) {
                     curPred = curPred.dominator();
                 }
@@ -615,7 +615,7 @@
                 if (cur.numberOfPreds() > 0) {
                     TTY.print("    preds: ");
                     for (int j = 0; j < cur.numberOfPreds(); j++) {
-                        BlockBegin pred = cur.predAt(j);
+                        BlockBegin pred = cur.predAt(j).begin();
                         TTY.print("B%d ", pred.blockID);
                     }
                 }
@@ -666,16 +666,17 @@
                 }
             }
 
-            for (BlockBegin pred : cur.blockPredecessors()) {
-                assert pred.linearScanNumber() >= 0 && pred.linearScanNumber() == linearScanOrder.indexOf(pred) : "incorrect linearScanNumber";
+            for (BlockEnd pred : cur.blockPredecessors()) {
+                BlockBegin begin = pred.begin();
+                assert begin.linearScanNumber() >= 0 && begin.linearScanNumber() == linearScanOrder.indexOf(begin) : "incorrect linearScanNumber";
                 if (!cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader)) {
-                    assert cur.linearScanNumber() > pred.linearScanNumber() : "invalid order";
+                    assert cur.linearScanNumber() > begin.linearScanNumber() : "invalid order";
                 }
-                if (cur.loopDepth() == pred.loopDepth()) {
-                    assert cur.loopIndex() == pred.loopIndex() || cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) : "successing blocks with same loop depth must have same loop index";
+                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() <= pred.linearScanNumber() : "dominator must be before predecessors";
+                assert cur.dominator().linearScanNumber() <= begin.linearScanNumber() : "dominator must be before predecessors";
             }
 
             // check dominator
@@ -684,7 +685,7 @@
             } else {
                 assert cur.dominator() != null : "all but first block must have dominator";
             }
-            assert cur.numberOfPreds() != 1 || cur.dominator() == cur.predAt(0) || cur.isExceptionEntry() : "Single predecessor must also be dominator";
+            assert cur.numberOfPreds() != 1 || cur.dominator() == cur.predAt(0).begin() || cur.isExceptionEntry() : "Single predecessor must also be dominator";
         }
 
         // check that all loops are continuous
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java	Fri May 13 15:18:41 2011 +0200
@@ -120,7 +120,7 @@
         if (block().isExceptionEntry()) {
             state = block().exceptionHandlerStates().get(i);
         } else {
-            state = block().blockPredecessors().get(i).end().stateAfter();
+            state = block().blockPredecessors().get(i).stateAfter();
         }
         return inputIn(state);
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRList.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIRList.java	Fri May 13 15:18:41 2011 +0200
@@ -438,7 +438,7 @@
         if (x.numberOfPreds() > 0) {
             TTY.print("preds: ");
             for (int i = 0; i < x.numberOfPreds(); i++) {
-                TTY.print("B%d ", x.predAt(i).blockID);
+                TTY.print("B%d ", x.predAt(i).begin().blockID);
             }
         }
 
--- a/graal/GraalGraph/src/com/oracle/graal/graph/Node.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalGraph/src/com/oracle/graal/graph/Node.java	Fri May 13 15:18:41 2011 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,37 +22,35 @@
  */
 package com.oracle.graal.graph;
 
-import java.util.AbstractList;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Iterator;
+import java.util.List;
 
 public abstract class Node implements Cloneable {
 
     public static final Node Null = null;
     public static final int DeletedID = -1;
 
-    private final Graph graph;
+    final Graph graph;
     private int id;
-    private final NodeArray inputs;
-    private final NodeArray successors;
-    private final ArrayList<Node> usages;
-    private final ArrayList<Node> predecessors;
+    final NodeArray inputs;
+    final NodeArray successors;
+    final ArrayList<Node> usages;
+    final ArrayList<Node> predecessors;
 
     public Node(int inputCount, int successorCount, Graph graph) {
         assert graph != null;
         this.graph = graph;
         this.id = graph.register(this);
-        this.inputs = new NodeArray(inputCount);
-        this.successors = new NodeArray(successorCount);
+        this.inputs = new NodeArray(this, inputCount);
+        this.successors = new NodeArray(this, successorCount);
         this.predecessors = new ArrayList<Node>();
         this.usages = new ArrayList<Node>();
     }
 
-    public Collection<Node> predecessors() {
-        return Collections.unmodifiableCollection(predecessors);
+    public List<Node> predecessors() {
+        return Collections.unmodifiableList(predecessors);
     }
 
     public Collection<Node> usages() {
@@ -110,6 +108,7 @@
         for (int i = 0; i < successors.size(); ++i) {
             successors.set(i, Null);
         }
+        assert predecessors().size() == 0 && usages().size() == 0;
         // make sure its not connected. pred usages
         graph.unregister(this);
         id = DeletedID;
@@ -147,77 +146,4 @@
     public String toString() {
         return this.getClass().getSimpleName() + "-" + this.id();
     }
-
-    public class NodeArray extends AbstractList<Node> {
-
-        private final Node[] nodes;
-
-        public NodeArray(int length) {
-            this.nodes = new Node[length];
-        }
-
-        public Iterator<Node> iterator() {
-            return Arrays.asList(this.nodes).iterator();
-        }
-
-        private Node self() {
-            return Node.this;
-        }
-
-        public Node set(int index, Node node) {
-            assert node == Null || node.graph == self().graph;
-            Node old = nodes[index];
-
-            if (old != node) {
-                nodes[index] = node;
-                if (Node.this.inputs == this) {
-                    if (old != null) {
-                        old.usages.remove(self());
-                    }
-                    if (node != null) {
-                        node.usages.add(self());
-                    }
-                } else {
-                    assert Node.this.successors == this;
-                    if (old != null) {
-                        old.predecessors.remove(self());
-                    }
-                    if (node != null) {
-                        node.predecessors.add(self());
-                    }
-                }
-            }
-
-            return old;
-        }
-
-        public void setAll(NodeArray other) {
-            assert size() == other.size();
-            for (int i = 0; i < other.size(); i++) {
-                set(i, other.get(i));
-            }
-        }
-
-        public Node get(int index) {
-            return nodes[index];
-        }
-
-        public Node[] toArray() {
-            return Arrays.copyOf(nodes, nodes.length);
-        }
-
-        private boolean replaceFirstOccurrence(Node toReplace, Node replacement) {
-            for (int i = 0; i < nodes.length; i++) {
-                if (nodes[i] == toReplace) {
-                    nodes[i] = replacement;
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public int size() {
-            return nodes.length;
-        }
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/GraalGraph/src/com/oracle/graal/graph/NodeArray.java	Fri May 13 15:18:41 2011 +0200
@@ -0,0 +1,133 @@
+/*
+ * 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.oracle.graal.graph;
+
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Iterator;
+
+public class NodeArray extends AbstractList<Node> {
+
+    private final Node node;
+    private final Node[] nodes;
+
+    public NodeArray(Node node, int length) {
+        this.node = node;
+        this.nodes = new Node[length];
+    }
+
+    public Iterator<Node> iterator() {
+        return Arrays.asList(this.nodes).iterator();
+    }
+
+    private Node self() {
+        return this.node;
+    }
+
+    public Node set(int index, Node node) {
+        assert node == Node.Null || node.graph == self().graph;
+        assert node == Node.Null || node.id() != Node.DeletedID;
+        Node old = nodes[index];
+
+        if (old != node) {
+            nodes[index] = node;
+            if (self().inputs == this) {
+                if (old != null) {
+                    old.usages.remove(self());
+                }
+                if (node != null) {
+                    node.usages.add(self());
+                }
+            } else {
+                assert self().successors == this;
+                if (old != null) {
+                    old.predecessors.remove(self());
+                }
+                if (node != null) {
+                    node.predecessors.add(self());
+                }
+            }
+        }
+
+        return old;
+    }
+
+    /**
+     * Sets the specified input/successor to the given node, and inserts the back edge (usage/predecessor) at the given index.
+     */
+    public Node set(int index, Node node, int backIndex) {
+        assert node == Node.Null || node.graph == self().graph;
+        Node old = nodes[index];
+
+        if (old != node) {
+            nodes[index] = node;
+            if (self().inputs == this) {
+                if (old != null) {
+                    old.usages.remove(self());
+                }
+                if (node != null) {
+                    node.usages.add(backIndex, self());
+                }
+            } else {
+                assert self().successors == this;
+                if (old != null) {
+                    old.predecessors.remove(self());
+                }
+                if (node != null) {
+                    node.predecessors.add(backIndex, self());
+                }
+            }
+        }
+
+        return old;
+    }
+
+    public void setAll(NodeArray other) {
+        assert size() == other.size();
+        for (int i = 0; i < other.size(); i++) {
+            set(i, other.get(i));
+        }
+    }
+
+    public Node get(int index) {
+        return nodes[index];
+    }
+
+    public Node[] toArray() {
+        return Arrays.copyOf(nodes, nodes.length);
+    }
+
+    boolean replaceFirstOccurrence(Node toReplace, Node replacement) {
+        for (int i = 0; i < nodes.length; i++) {
+            if (nodes[i] == toReplace) {
+                nodes[i] = replacement;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public int size() {
+        return nodes.length;
+    }
+}
--- a/graal/GraalGraphviz/src/com/oracle/graal/graph/vis/GraphvizPrinter.java	Fri May 13 11:19:25 2011 +0200
+++ b/graal/GraalGraphviz/src/com/oracle/graal/graph/vis/GraphvizPrinter.java	Fri May 13 15:18:41 2011 +0200
@@ -25,10 +25,12 @@
 import java.awt.Color;
 import java.io.OutputStream;
 import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.HashSet;
 
 import com.oracle.graal.graph.Graph;
 import com.oracle.graal.graph.Node;
-import com.oracle.graal.graph.Node.NodeArray;
+import com.oracle.graal.graph.NodeArray;
 
 /**
  * Generates a representation of {@link Node Nodes} or entire {@link Graph Graphs} in the DOT language that can be
@@ -44,6 +46,7 @@
     }
 
     private final PrintStream out;
+    private final HashSet<Class<?>> omittedClasses = new HashSet<Class<?>>();
 
     /**
      * Creates a new {@link GraphvizPrinter} that writes to the specified output stream.
@@ -52,6 +55,10 @@
         this.out = new PrintStream(out);
     }
 
+    public void addOmittedClass(Class<?> clazz) {
+        omittedClasses.add(clazz);
+    }
+
     /**
      * Opens a graph with the specified title (label). Call this before printing any nodes, but not more than once
      * without calling {@link #end()} first.
@@ -90,6 +97,9 @@
      * Prints a single node and edges for all its inputs and successors.
      */
     public void printNode(Node node, boolean shortNames) {
+        if (omittedClasses.contains(node.getClass())) {
+            return;
+        }
         int id = node.id();
         String name = "n" + id;
         NodeArray inputs = node.inputs();
@@ -103,14 +113,14 @@
 
         for (int i = 0; i < successors.size(); ++i) {
             Node successor = successors.get(i);
-            if (successor != Node.Null) {
+            if (successor != Node.Null && !omittedClasses.contains(successor.getClass())) {
                 printControlEdge(id, i, successor.id());
             }
         }
 
         for (int i = 0; i < inputs.size(); ++i) {
             Node input = inputs.get(i);
-            if (input != Node.Null) {
+            if (input != Node.Null && !omittedClasses.contains(input.getClass())) {
                 if (node.getClass().getSimpleName().equals("FrameState") && input.getClass().getSimpleName().equals("Local")) {
                     continue;
                 }
@@ -141,6 +151,7 @@
         label = label.replace("&", "&amp;");
         label = label.replace("<", "&lt;");
         label = label.replace(">", "&gt;");
+        label = label.replace("\"", "&quot;");
         out.println("    </TR></TABLE></TD></TR><TR><TD BORDER=\"1\" COLSPAN=\"3\" BGCOLOR=\"" + NODE_BGCOLOR_STRING + "\">" + label + "</TD></TR>");
         out.println("    <TR><TD COLSPAN=\"2\" CELLPADDING=\"0\" ALIGN=\"RIGHT\"><TABLE BORDER=\"0\" CELLSPACING=\"2\" CELLPADDING=\"0\"><TR>");
 
--- a/runscimark.sh	Fri May 13 11:19:25 2011 +0200
+++ b/runscimark.sh	Fri May 13 15:18:41 2011 +0200
@@ -16,11 +16,12 @@
   exit 1;
 fi
 COUNT=$1
+shift
 if [ -z "${COUNT}" ]; then
   COUNT=5000
 fi
 for (( i = 1; i <= ${COUNT}; i++ ))      ### Outer for loop ###
 do
   echo "$i "
-  ${JDK7}/jre/bin/java -client -d64 -graal -esa -ea -Xms32m -Xmx100m -Xbootclasspath/a:${SCIMARK} -C1X:+PrintTimers  jnt.scimark2.commandline -large
+  ${JDK7}/jre/bin/java -client -d64 -graal -esa -ea -Xms32m -Xmx100m -Xbootclasspath/a:${SCIMARK} -C1X:+PrintTimers $@ jnt.scimark2.commandline -large
 done
--- a/src/share/vm/c1x/c1x_Compiler.cpp	Fri May 13 11:19:25 2011 +0200
+++ b/src/share/vm/c1x/c1x_Compiler.cpp	Fri May 13 15:18:41 2011 +0200
@@ -53,7 +53,8 @@
   JNIEnv *env = ((JavaThread *) Thread::current())->jni_environment();
   jclass klass = env->FindClass("com/oracle/graal/runtime/VMEntriesNative");
   if (klass == NULL) {
-    fatal("c1x VMEntries class not found");
+    tty->print_cr("c1x VMEntries class not found");
+    vm_abort(false);
   }
   env->RegisterNatives(klass, VMEntries_methods, VMEntries_methods_count());
 
@@ -72,7 +73,10 @@
       const char* arg = Arguments::c1x_args_array()[i];
       Handle option = java_lang_String::create_from_str(arg, THREAD);
       jboolean result = VMExits::setOption(option);
-      if (!result) fatal("Invalid option for C1X!");
+      if (!result) {
+        tty->print_cr("Invalid option for C1X!");
+        vm_abort(false);
+      }
     }
 
     VMExits::initializeCompiler();