changeset 2707:7ed72769d51a

exception handling related changes: * changed blockPredecessors to list of Instructions, instead of Blocks * removed explicit predecessor management in BlockBegin, now using predecessors from Graph structure * replaced generated LIR exception entries with exception dispatch chains in IR * added Unwind and ExceptionDispatch instructions * removed ExceptionEntry flag in BlockBegin and all code depending on it * removed exceptionHandler list from Instruction, replaced by exception Edge on Invoke and Throw * replaced list of ExceptionHandlers with single exception edge in debug info misc: * changed GraphvizPrinter layout (smaller ports on large nodes) * removed defunct run config
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 18 May 2011 18:09:20 +0200
parents 0ea5f12e873a
children 4272b7af2d17
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/EdgeMoveOptimizer.java graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java graal/GraalCompiler/src/com/sun/c1x/alloc/RegisterVerifier.java graal/GraalCompiler/src/com/sun/c1x/asm/ExceptionInfo.java graal/GraalCompiler/src/com/sun/c1x/asm/TargetMethodAssembler.java graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.java 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/BlockEnd.java graal/GraalCompiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java graal/GraalCompiler/src/com/sun/c1x/ir/ExceptionDispatch.java graal/GraalCompiler/src/com/sun/c1x/ir/Instruction.java graal/GraalCompiler/src/com/sun/c1x/ir/Invoke.java graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java graal/GraalCompiler/src/com/sun/c1x/ir/StateSplit.java graal/GraalCompiler/src/com/sun/c1x/ir/Throw.java graal/GraalCompiler/src/com/sun/c1x/ir/Unwind.java graal/GraalCompiler/src/com/sun/c1x/ir/ValueVisitor.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/LIRDebugInfo.java graal/GraalCompiler/src/com/sun/c1x/lir/LIRInstruction.java graal/GraalCompiler/src/com/sun/c1x/lir/LIRList.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/value/FrameState.java graal/GraalCompiler/src/com/sun/c1x/value/FrameStateAccess.java graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java graal/GraalGraphviz/src/com/oracle/graal/graph/vis/GraphvizPrinter.java graal/hotspot/hotspot Default.launch
diffstat 35 files changed, 671 insertions(+), 790 deletions(-) [+]
line wrap: on
line diff
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Wed May 18 18:09:20 2011 +0200
@@ -266,9 +266,6 @@
             // generate code for slow cases
             lirAssembler.emitLocalStubs();
 
-            // generate exception adapters
-            lirAssembler.emitExceptionEntries();
-
             // generate deoptimization stubs
             ArrayList<DeoptimizationStub> deoptimizationStubs = lirGenerator.deoptimizationStubs();
             if (deoptimizationStubs != null) {
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/ControlFlowOptimizer.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/ControlFlowOptimizer.java	Wed May 18 18:09:20 2011 +0200
@@ -101,9 +101,7 @@
     // must always end with an unconditional branch to this successor
     private boolean canDeleteBlock(BlockBegin block) {
         if (block.numberOfSux() != 1 ||
-            block.numberOfExceptionHandlers() != 0 ||
             block == ir.startBlock ||
-            block.isExceptionEntry() ||
             block.suxAt(0) == block) {
             return false;
         }
@@ -138,8 +136,8 @@
                 }
 
                 // update the block references in any branching LIR instructions
-                for (BlockEnd pred : block.blockPredecessors()) {
-                    for (LIRInstruction instr : pred.begin().lir().instructionsList()) {
+                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) {
@@ -228,7 +226,7 @@
                 CiValue returnOpr = ((LIROp1) curLastOp).operand();
 
                 for (int j = block.numberOfPreds() - 1; j >= 0; j--) {
-                    BlockBegin pred = block.predAt(j).begin();
+                    BlockBegin pred = block.predAt(j).block();
                     List<LIRInstruction> predInstructions = pred.lir().instructionsList();
                     LIRInstruction predLastOp = predInstructions.get(predInstructions.size() - 1);
 
@@ -263,8 +261,8 @@
                 assert code.contains(sux) : "missing successor from: " + block + "to: " + sux;
             }
 
-            for (BlockEnd pred : block.blockPredecessors()) {
-                assert code.contains(pred.begin()) : "missing predecessor from: " + block + "to: " + pred.begin();
+            for (Instruction pred : block.blockPredecessors()) {
+                assert code.contains(pred.block()) : "missing predecessor from: " + block + "to: " + pred.block();
             }
         }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/EdgeMoveOptimizer.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/EdgeMoveOptimizer.java	Wed May 18 18:09:20 2011 +0200
@@ -66,7 +66,7 @@
         for (int i = blockList.size() - 1; i >= 1; i--) {
             BlockBegin block = blockList.get(i);
 
-            if (block.numberOfPreds() > 1 && !block.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry)) {
+            if (block.numberOfPreds() > 1) {
                 optimizer.optimizeMovesAtBlockEnd(block);
             }
             if (block.numberOfSux() == 2) {
@@ -122,11 +122,10 @@
 
         int numPreds = block.numberOfPreds();
         assert numPreds > 1 : "do not call otherwise";
-        assert !block.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry) : "exception handlers not allowed";
 
         // setup a list with the LIR instructions of all predecessors
         for (int i = 0; i < numPreds; i++) {
-            BlockBegin pred = block.predAt(i).begin();
+            BlockBegin pred = block.predAt(i).block();
             List<LIRInstruction> predInstructions = pred.lir().instructionsList();
 
             if (pred.numberOfSux() != 1) {
@@ -231,8 +230,7 @@
                 // the same blocks.
                 return;
             }
-            assert sux.predAt(0).begin() == block : "invalid control flow";
-            assert !sux.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry) : "exception handlers not allowed";
+            assert sux.predAt(0).block() == block : "invalid control flow";
 
             // ignore the label at the beginning of the block
             List<LIRInstruction> seq = suxInstructions.subList(1, suxInstructions.size());
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Wed May 18 18:09:20 2011 +0200
@@ -28,18 +28,18 @@
 import java.util.*;
 
 import com.sun.c1x.*;
-import com.sun.c1x.alloc.Interval.*;
+import com.sun.c1x.alloc.Interval.RegisterBinding;
+import com.sun.c1x.alloc.Interval.RegisterPriority;
+import com.sun.c1x.alloc.Interval.SpillState;
 import com.sun.c1x.debug.*;
 import com.sun.c1x.gen.*;
 import com.sun.c1x.graph.*;
 import com.sun.c1x.ir.*;
-import com.sun.c1x.ir.BlockBegin.BlockFlag;
 import com.sun.c1x.lir.*;
 import com.sun.c1x.lir.LIRInstruction.OperandMode;
 import com.sun.c1x.observer.*;
 import com.sun.c1x.util.*;
 import com.sun.c1x.value.*;
-import com.sun.c1x.value.FrameState.PhiProcedure;
 import com.sun.c1x.value.FrameState.ValueProcedure;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
@@ -599,17 +599,6 @@
             final CiBitMap liveGen = new CiBitMap(liveSize);
             final CiBitMap liveKill = new CiBitMap(liveSize);
 
-            if (block.isExceptionEntry()) {
-                // Phi functions at the begin of an exception handler are
-                // implicitly defined (= killed) at the beginning of the block.
-                block.stateBefore().forEachLivePhi(block, new PhiProcedure() {
-                    public boolean doPhi(Phi phi) {
-                        liveKill.set(operandNumber(phi.operand()));
-                        return true;
-                    }
-                });
-            }
-
             List<LIRInstruction> instructions = block.lir().instructionsList();
             int numInst = instructions.size();
 
@@ -773,8 +762,7 @@
 
                 // liveOut(block) is the union of liveIn(sux), for successors sux of block
                 int n = block.numberOfSux();
-                int e = block.numberOfExceptionHandlers();
-                if (n + e > 0) {
+                if (n > 0) {
                     // block has successors
                     if (n > 0) {
                         liveOut.setFrom(block.suxAt(0).lirBlock.liveIn);
@@ -784,9 +772,6 @@
                     } else {
                         liveOut.clearAll();
                     }
-                    for (int j = 0; j < e; j++) {
-                        liveOut.setUnion(block.exceptionHandlerAt(j).lirBlock.liveIn);
-                    }
 
                     if (!lirBlock.liveOut.isSame(liveOut)) {
                         // A change occurred. Swap the old and new live out sets to avoid copying.
@@ -1282,19 +1267,19 @@
             } // end of instruction iteration
 
             // (tw) Make sure that no spill store optimization is applied for phi instructions that flow into exception handlers.
-            if (block.isExceptionEntry()) {
-                FrameState stateBefore = block.stateBefore();
-                stateBefore.forEachLivePhi(block, new PhiProcedure() {
-                    @Override
-                    public boolean doPhi(Phi phi) {
-                        Interval interval = intervalFor(phi.operand());
-                        if (interval != null) {
-                            interval.setSpillState(SpillState.NoOptimization);
-                        }
-                        return true;
-                    }
-                });
-            }
+//            if (block.isExceptionEntry()) {
+//                FrameState stateBefore = block.stateBefore();
+//                stateBefore.forEachLivePhi(block, new PhiProcedure() {
+//                    @Override
+//                    public boolean doPhi(Phi phi) {
+//                        Interval interval = intervalFor(phi.operand());
+//                        if (interval != null) {
+//                            interval.setSpillState(SpillState.NoOptimization);
+//                        }
+//                        return true;
+//                    }
+//                });
+//            }
 
         } // end of block iteration
 
@@ -1596,7 +1581,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).begin() : "all critical edges must be broken";
+                    assert fromBlock == toBlock.predAt(i).block() : "all critical edges must be broken";
                 }
             }
 
@@ -1619,7 +1604,7 @@
             BlockBegin block = blockAt(i);
 
             // check if block has only one predecessor and only one successor
-            if (block.numberOfPreds() == 1 && block.numberOfSux() == 1 && block.numberOfExceptionHandlers() == 0 && !block.isExceptionEntry()) {
+            if (block.numberOfPreds() == 1 && block.numberOfSux() == 1) {
                 List<LIRInstruction> instructions = block.lir().instructionsList();
                 assert instructions.get(0).code == LIROpcode.Label : "block must start with label";
                 assert instructions.get(instructions.size() - 1).code == LIROpcode.Branch : "block with successors must end with branch";
@@ -1627,7 +1612,7 @@
 
                 // check if block is empty (only label and branch)
                 if (instructions.size() == 2) {
-                    BlockBegin pred = block.predAt(0).begin();
+                    BlockBegin pred = block.predAt(0).block();
                     BlockBegin sux = block.suxAt(0);
 
                     // prevent optimization of two consecutive blocks
@@ -1676,191 +1661,6 @@
         }
     }
 
-    void resolveExceptionEntry(BlockBegin block, CiValue operand, MoveResolver moveResolver) {
-        if (intervalFor(operand) == null) {
-            // if a phi function is never used, no interval is created . ignore this
-            return;
-        }
-
-        Interval interval = intervalAtBlockBegin(block, operand);
-        CiValue location = interval.location();
-
-        if (location.isRegister() && interval.alwaysInMemory()) {
-            // the interval is split to get a short range that is located on the stack
-            // in the following two cases:
-            // * the interval started in memory (e.g. method parameter), but is currently in a register
-            // this is an optimization for exception handling that reduces the number of moves that
-            // are necessary for resolving the states when an exception uses this exception handler
-            // * the interval would be on the fpu stack at the begin of the exception handler
-            // this is not allowed because of the complicated fpu stack handling on Intel
-
-            // range that will be spilled to memory
-            int fromOpId = block.firstLirInstructionId();
-            int toOpId = fromOpId + 1; // short live range of length 1
-            assert interval.from() <= fromOpId && interval.to() >= toOpId : "no split allowed between exception entry and first instruction";
-
-            if (interval.from() != fromOpId) {
-                // the part before fromOpId is unchanged
-                interval = interval.split(fromOpId, this);
-                interval.assignLocation(location);
-            }
-            assert interval.from() == fromOpId : "must be true now";
-
-            Interval spilledPart = interval;
-            if (interval.to() != toOpId) {
-                // the part after toOpId is unchanged
-                spilledPart = interval.splitFromStart(toOpId, this);
-                moveResolver.addMapping(spilledPart, interval);
-            }
-            assignSpillSlot(spilledPart);
-
-            assert spilledPart.from() == fromOpId && spilledPart.to() == toOpId : "just checking";
-        }
-    }
-
-    void resolveExceptionEntry(final BlockBegin block, final MoveResolver moveResolver) {
-        assert block.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry) : "should not call otherwise";
-        assert moveResolver.checkEmpty();
-
-        // visit all registers where the liveIn bit is set
-        for (int operandNum = block.lirBlock.liveIn.nextSetBit(0); operandNum >= 0; operandNum = block.lirBlock.liveIn.nextSetBit(operandNum + 1)) {
-            resolveExceptionEntry(block, operands.operandFor(operandNum), moveResolver);
-        }
-
-        // the liveIn bits are not set for phi functions of the xhandler entry, so iterate them separately
-        block.stateBefore().forEachLivePhi(block, new PhiProcedure() {
-            public boolean doPhi(Phi phi) {
-                resolveExceptionEntry(block, phi.operand(), moveResolver);
-                return true;
-            }
-        });
-
-        if (moveResolver.hasMappings()) {
-            // insert moves after first instruction
-            moveResolver.setInsertPosition(block.lir(), 0);
-            moveResolver.resolveAndAppendMoves();
-        }
-    }
-
-    void resolveExceptionEdge(ExceptionHandler handler, int throwingOpId, CiValue operand, Phi phi, MoveResolver moveResolver) {
-        if (intervalFor(operand) == null) {
-            // if a phi function is never used, no interval is created . ignore this
-            return;
-        }
-
-        // the computation of toInterval is equal to resolveCollectMappings,
-        // but fromInterval is more complicated because of phi functions
-        BlockBegin toBlock = handler.entryBlock();
-        Interval toInterval = intervalAtBlockBegin(toBlock, operand);
-
-        if (phi != null) {
-            // phi function of the exception entry block
-            // no moves are created for this phi function in the LIRGenerator, so the
-            // interval at the throwing instruction must be searched using the operands
-            // of the phi function
-            Value fromValue = phi.inputAt(handler.phiOperand());
-            Constant con = null;
-            if (fromValue instanceof Constant) {
-                con = (Constant) fromValue;
-            }
-            if (con != null && (con.operand().isIllegal() || con.operand().isConstant())) {
-                // unpinned constants may have no register, so add mapping from constant to interval
-                moveResolver.addMapping(con.asConstant(), toInterval);
-            } else {
-                // search split child at the throwing opId
-                Interval fromInterval = intervalAtOpId(fromValue.operand(), throwingOpId);
-                if (fromInterval != toInterval) {
-                    moveResolver.addMapping(fromInterval, toInterval);
-                    // with phi functions it can happen that the same fromValue is used in
-                    // multiple mappings, so notify move-resolver that this is allowed
-                    moveResolver.setMultipleReadsAllowed();
-                }
-            }
-        } else {
-            // no phi function, so use regNum also for fromInterval
-            // search split child at the throwing opId
-            Interval fromInterval = intervalAtOpId(operand, throwingOpId);
-            if (fromInterval != toInterval) {
-                // optimization to reduce number of moves: when toInterval is on stack and
-                // the stack slot is known to be always correct, then no move is necessary
-                if (!fromInterval.alwaysInMemory() || fromInterval.spillSlot() != toInterval.location()) {
-                    moveResolver.addMapping(fromInterval, toInterval);
-                }
-            }
-        }
-    }
-
-    void resolveExceptionEdge(final ExceptionHandler handler, final int throwingOpId, final MoveResolver moveResolver) {
-        if (C1XOptions.TraceLinearScanLevel >= 4) {
-            TTY.println("resolving exception handler B%d: throwingOpId=%d", handler.entryBlock().blockID, throwingOpId);
-        }
-
-        assert moveResolver.checkEmpty();
-        assert handler.lirOpId() == -1 : "already processed this xhandler";
-        handler.setLirOpId(throwingOpId);
-        assert handler.entryCode() == null : "code already present";
-
-        // visit all registers where the liveIn bit is set
-        BlockBegin block = handler.entryBlock();
-        for (int operandNum = block.lirBlock.liveIn.nextSetBit(0); operandNum >= 0; operandNum = block.lirBlock.liveIn.nextSetBit(operandNum + 1)) {
-            resolveExceptionEdge(handler, throwingOpId, operands.operandFor(operandNum), null, moveResolver);
-        }
-
-        // the liveIn bits are not set for phi functions of the xhandler entry, so iterate them separately
-        block.stateBefore().forEachLivePhi(block, new PhiProcedure() {
-            public boolean doPhi(Phi phi) {
-                resolveExceptionEdge(handler, throwingOpId, phi.operand(), phi, moveResolver);
-                return true;
-            }
-        });
-
-        if (moveResolver.hasMappings()) {
-            LIRList entryCode = new LIRList(gen);
-            moveResolver.setInsertPosition(entryCode, 0);
-            moveResolver.resolveAndAppendMoves();
-
-            entryCode.jump(handler.entryBlock());
-            handler.setEntryCode(entryCode);
-        }
-    }
-
-    void resolveExceptionHandlers() {
-        MoveResolver moveResolver = new MoveResolver(this);
-        //LIRVisitState visitor = new LIRVisitState();
-        int numBlocks = blockCount();
-
-        int i;
-        for (i = 0; i < numBlocks; i++) {
-            BlockBegin block = blockAt(i);
-            if (block.checkBlockFlag(BlockFlag.ExceptionEntry)) {
-                resolveExceptionEntry(block, moveResolver);
-            }
-        }
-
-        for (i = 0; i < numBlocks; i++) {
-            BlockBegin block = blockAt(i);
-            LIRList ops = block.lir();
-            int numOps = ops.length();
-
-            // iterate all instructions of the block. skip the first because it is always a label
-            assert !ops.at(0).hasOperands() : "first operation must always be a label";
-            for (int j = 1; j < numOps; j++) {
-                LIRInstruction op = ops.at(j);
-                int opId = op.id;
-
-                if (opId != -1 && op.info != null) {
-                    // visit operation to collect all operands
-                    for (ExceptionHandler handler : op.exceptionEdges()) {
-                        resolveExceptionEdge(handler, opId, moveResolver);
-                    }
-
-                } else if (C1XOptions.DetailedAsserts) {
-                    assert op.exceptionEdges().size() == 0 : "missed exception handler";
-                }
-            }
-        }
-    }
-
     // * Phase 7: assign register numbers back to LIR
     // (includes computation of debug information and oop maps)
 
@@ -2172,13 +1972,11 @@
 
             if (op.info != null) {
                 // exception handling
-                if (compilation.hasExceptionHandlers()) {
-                    for (ExceptionHandler handler : op.exceptionEdges()) {
-                        if (handler.entryCode() != null) {
-                            assignLocations(handler.entryCode().instructionsList(), null);
-                        }
-                    }
-                }
+//                if (compilation.hasExceptionHandlers()) {
+//                    if (op.exceptionEdge() != null && op.exceptionEdge().lir() != null) {
+//                        assignLocations(op.exceptionEdge().lir().instructionsList(), iw);
+//                    }
+//                }
 
                 // compute reference map and debug information
                 computeDebugInfo(iw, op);
@@ -2252,9 +2050,6 @@
         }
 
         resolveDataFlow();
-        if (compilation.hasExceptionHandlers()) {
-            resolveExceptionHandlers();
-        }
 
         if (C1XOptions.PrintTimers) {
             C1XTimers.RESOLUTION.stop();
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/RegisterVerifier.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/RegisterVerifier.java	Wed May 18 18:09:20 2011 +0200
@@ -134,18 +134,18 @@
         }
     }
 
-    void processXhandler(ExceptionHandler xhandler, Interval[] inputState) {
+    void processXhandler(BlockBegin xhandler, Interval[] inputState) {
         if (C1XOptions.TraceLinearScanLevel >= 2) {
-            TTY.println("processXhandler B%d", xhandler.entryBlock().blockID);
+            TTY.println("processXhandler B%d", xhandler.blockID);
         }
 
         // must copy state because it is modified
         inputState = copy(inputState);
 
-        if (xhandler.entryCode() != null) {
-            processOperations(xhandler.entryCode(), inputState);
+        if (xhandler.lir() != null) {
+            processOperations(xhandler.lir(), inputState);
         }
-        processSuccessor(xhandler.entryBlock(), inputState);
+        processSuccessor(xhandler, inputState);
     }
 
     void processSuccessor(BlockBegin block, Interval[] inputState) {
@@ -260,10 +260,8 @@
             }
 
             // process xhandler before output and temp operands
-            List<ExceptionHandler> xhandlers = op.exceptionEdges();
-            n = xhandlers.size();
-            for (int k = 0; k < n; k++) {
-                processXhandler(xhandlers.get(k), inputState);
+            if (op.exceptionEdge() != null) {
+                processXhandler(op.exceptionEdge(), inputState);
             }
 
             // set temp operands (some operations use temp operands also as output operands, so can't set them null)
--- a/graal/GraalCompiler/src/com/sun/c1x/asm/ExceptionInfo.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/asm/ExceptionInfo.java	Wed May 18 18:09:20 2011 +0200
@@ -22,8 +22,6 @@
  */
 package com.sun.c1x.asm;
 
-import java.util.*;
-
 import com.sun.c1x.ir.*;
 
 /**
@@ -33,12 +31,12 @@
 public class ExceptionInfo {
 
     public final int codeOffset;
-    public final List<ExceptionHandler> exceptionHandlers;
+    public final BlockBegin exceptionEdge;
     public final int bci;
 
-    public ExceptionInfo(int pcOffset, List<ExceptionHandler> exceptionHandlers, int bci) {
+    public ExceptionInfo(int pcOffset, BlockBegin exceptionEdge, int bci) {
         this.codeOffset = pcOffset;
-        this.exceptionHandlers = exceptionHandlers;
+        this.exceptionEdge = exceptionEdge;
         this.bci = bci;
     }
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/asm/TargetMethodAssembler.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/asm/TargetMethodAssembler.java	Wed May 18 18:09:20 2011 +0200
@@ -27,7 +27,6 @@
 import com.oracle.max.asm.*;
 import com.sun.c1x.*;
 import com.sun.c1x.debug.*;
-import com.sun.c1x.ir.*;
 import com.sun.c1x.lir.*;
 import com.sun.c1x.util.*;
 import com.sun.cri.ci.*;
@@ -65,11 +64,7 @@
         if (exceptionInfoList != null) {
             for (ExceptionInfo ei : exceptionInfoList) {
                 int codeOffset = ei.codeOffset;
-                for (ExceptionHandler handler : ei.exceptionHandlers) {
-                    int entryOffset = handler.entryCodeOffset();
-                    RiType caughtType = handler.handler.catchType();
-                    targetMethod.recordExceptionHandler(codeOffset, ei.bci, 0, entryOffset, handler.handlerBCI(), caughtType);
-                }
+                targetMethod.recordExceptionHandler(codeOffset, -1, 0, ei.exceptionEdge.lirBlock.blockEntryPco, -1, null);
             }
         }
 
@@ -145,11 +140,11 @@
 
     public void recordExceptionHandlers(int pcOffset, LIRDebugInfo info) {
         if (info != null) {
-            if (info.exceptionHandlers != null) {
+            if (info.exceptionEdge != null) {
                 if (exceptionInfoList == null) {
                     exceptionInfoList = new ArrayList<ExceptionInfo>(4);
                 }
-                exceptionInfoList.add(new ExceptionInfo(pcOffset, info.exceptionHandlers, info.state.bci));
+                exceptionInfoList.add(new ExceptionInfo(pcOffset, info.exceptionEdge, info.state.bci));
             }
         }
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/debug/CFGPrinter.java	Wed May 18 18:09:20 2011 +0200
@@ -124,7 +124,7 @@
      * @param printHIR if {@code true} the HIR for each instruction in the block will be printed
      * @param printLIR if {@code true} the LIR for each instruction in the block will be printed
      */
-    void printBlock(BlockBegin block, List<BlockBegin> successors, Iterable<BlockBegin> handlers, boolean printHIR, boolean printLIR) {
+    void printBlock(BlockBegin block, List<BlockBegin> successors, BlockBegin handler, boolean printHIR, boolean printLIR) {
         begin("block");
 
         out.print("name \"B").print(block.blockID).println('"');
@@ -132,8 +132,8 @@
         out.print("to_bci ").println(block.end() == null ? -1 : block.end().bci());
 
         out.print("predecessors ");
-        for (BlockEnd pred : block.blockPredecessors()) {
-            out.print("\"B").print(pred.begin().blockID).print("\" ");
+        for (Instruction pred : block.blockPredecessors()) {
+            out.print("\"B").print(pred.block().blockID).print("\" ");
         }
         out.println();
 
@@ -144,15 +144,12 @@
         out.println();
 
         out.print("xhandlers");
-        for (BlockBegin handler : handlers) {
+        if (handler != null) {
             out.print("\"B").print(handler.blockID).print("\" ");
         }
         out.println();
 
         out.print("flags ");
-        if (block.isExceptionEntry()) {
-            out.print("\"ex\" ");
-        }
         if (block.isSubroutineEntry()) {
             out.print("\"sr\" ");
         }
@@ -587,7 +584,7 @@
         startBlock.iteratePreOrder(new BlockClosure() {
             public void apply(BlockBegin block) {
                 List<BlockBegin> successors = block.end() != null ? block.end().blockSuccessors() : new ArrayList<BlockBegin>(0);
-                printBlock(block, successors, block.exceptionHandlerBlocks(), printHIR, printLIR);
+                printBlock(block, successors, block.exceptionEdge(), printHIR, printLIR);
             }
         });
         end("cfg");
--- a/graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.java	Wed May 18 18:09:20 2011 +0200
@@ -394,7 +394,6 @@
 
     @Override
     public void visitExceptionObject(ExceptionObject x) {
-        assert currentBlock.isExceptionEntry() : "ExceptionObject only allowed in exception handler block";
         assert currentBlock.next() == x : "ExceptionObject must be first instruction of block";
 
         // no moves are created for phi functions at the begin of exception
@@ -1446,7 +1445,7 @@
         }
 
         assert state != null;
-        return new LIRDebugInfo(state, x.exceptionHandlers());
+        return new LIRDebugInfo(state, x.exceptionEdge());
     }
 
     List<CiValue> visitInvokeArguments(CiCallingConvention cc, Invoke x, List<CiValue> pointerSlots) {
@@ -1611,4 +1610,15 @@
     public void visitFrameState(FrameState i) {
         // nothing to do for now
     }
+
+    @Override
+    public void visitUnwind(Unwind x) {
+        // TODO ls: this needs some thorough testing...
+        CiValue operand = resultOperandFor(x.kind);
+        CiValue result = force(x.exception(), operand);
+        ArrayList<CiValue> args = new ArrayList<CiValue>(1);
+        args.add(result);
+        lir.callRuntime(CiRuntimeCall.UnwindException, CiValue.IllegalValue, args, null);
+        setNoResult(x);
+    }
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/BlockUtil.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/BlockUtil.java	Wed May 18 18:09:20 2011 +0200
@@ -22,12 +22,12 @@
  */
 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.
- *
- * @author Ben L. Titzer
  */
 public class BlockUtil {
 
@@ -36,11 +36,10 @@
      * @param block the block to remove from the graph
      */
     public static void disconnectFromGraph(BlockBegin block) {
-        for (BlockEnd p : block.blockPredecessors()) {
-            p.blockSuccessors().remove(block);
+        ArrayList<Instruction> preds = new ArrayList<Instruction>(block.blockPredecessors());
+        for (Instruction p : preds) {
+            p.block().end().blockSuccessors().remove(block);
         }
-        for (BlockBegin s : block.end().blockSuccessors()) {
-            s.blockPredecessors().remove(block);
-        }
+        block.end().clearSuccessors();
     }
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Wed May 18 18:09:20 2011 +0200
@@ -111,7 +111,7 @@
 
     private final Graph graph;
 
-    private final List<BlockBegin> newExceptionHandlers = new ArrayList<BlockBegin>();
+    private BlockBegin unwindBlock;
 
     /**
      * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation.
@@ -150,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 blockMap = compilation.getBlockMap(rootMethod);
@@ -159,9 +159,6 @@
         for (int i = 0; i < blockMap.blocks.size(); i++) {
             BlockMap.Block block = blockMap.blocks.get(i);
             BlockBegin blockBegin = new BlockBegin(block.startBci, ir.nextBlockNumber(), graph);
-            if (block.isExceptionEntry) {
-                blockBegin.setBlockFlag(BlockBegin.BlockFlag.ExceptionEntry);
-            }
             if (block.isLoopHeader) {
                 blockBegin.setBlockFlag(BlockBegin.BlockFlag.ParserLoopHeader);
             }
@@ -204,7 +201,6 @@
 
             // 4A.3 setup an exception handler to unlock the root method synchronized object
             syncHandler = new BlockBegin(Instruction.SYNCHRONIZATION_ENTRY_BCI, ir.nextBlockNumber(), graph);
-            syncHandler.setExceptionEntry();
             syncHandler.setBlockFlag(BlockBegin.BlockFlag.IsOnWorkList);
             syncHandler.setBlockFlag(BlockBegin.BlockFlag.DefaultExceptionHandler);
 
@@ -262,69 +258,148 @@
         frameState.storeLocal(index, frameState.pop(kind));
     }
 
-    List<ExceptionHandler> handleException(Instruction x, int bci) {
+    private void handleException(Instruction x, int bci) {
         if (!hasHandler()) {
-            return ExceptionHandler.ZERO_HANDLERS;
+            return;
         }
 
         ArrayList<ExceptionHandler> exceptionHandlers = new ArrayList<ExceptionHandler>();
 
-        FrameState state = frameState.create(bci);
         assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == bci() : "invalid bci";
 
         // join with all potential exception handlers
         if (this.exceptionHandlers != null) {
             for (ExceptionHandler handler : this.exceptionHandlers) {
+                // if the handler covers this bytecode index, add it to the list
                 if (handler.covers(bci)) {
-                    // if the handler covers this bytecode index, add it to the list
-                    if (addExceptionHandler(exceptionHandlers, handler, state)) {
-                        // if the handler was a default handler, we are done
-                        return exceptionHandlers;
+                    ExceptionHandler newHandler = addExceptionHandler(handler, frameState);
+                    exceptionHandlers.add(newHandler);
+
+                    // stop when reaching catch all
+                    if (handler.isCatchAll()) {
+                        break;
                     }
                 }
             }
         }
 
-        return exceptionHandlers;
+        if (!exceptionHandlers.isEmpty()) {
+            BlockBegin successor;
+
+            ArrayList<BlockBegin> newBlocks = new ArrayList<BlockBegin>();
+
+            int current = exceptionHandlers.size() - 1;
+            if (exceptionHandlers.get(current).isCatchAll()) {
+                successor = exceptionHandlers.get(current).entryBlock();
+                current--;
+            } else {
+                if (unwindBlock == null) {
+                    unwindBlock = new BlockBegin(bci, ir.nextBlockNumber(), graph);
+                    Unwind unwind = new Unwind(null, false, graph);
+                    unwindBlock.appendNext(unwind, bci);
+                    unwindBlock.setEnd(unwind);
+                }
+                successor = unwindBlock;
+            }
+
+            for (; current >= 0; current--) {
+                ExceptionHandler handler = exceptionHandlers.get(current);
+
+                BlockBegin newSucc = null;
+                for (Instruction pred : successor.blockPredecessors()) {
+                    if (pred instanceof ExceptionDispatch) {
+                        ExceptionDispatch dispatch = (ExceptionDispatch) pred;
+                        if (dispatch.handler().handler == handler.handler) {
+                            newSucc = dispatch.begin();
+                            break;
+                        }
+                    }
+                }
+                if (newSucc != null) {
+                    successor = newSucc;
+                } else {
+                    BlockBegin dispatchEntry = new BlockBegin(handler.handlerBCI(), ir.nextBlockNumber(), graph);
+                    if (handler.handler.catchType().isResolved()) {
+                        ExceptionDispatch end = new ExceptionDispatch(null, handler.entryBlock(), null, handler, null, false, graph);
+                        end.setBlockSuccessor(0, successor);
+                        dispatchEntry.appendNext(end, handler.handlerBCI());
+                        dispatchEntry.setEnd(end);
+                    } else {
+                        Deoptimize deopt = new Deoptimize(graph, null);
+                        dispatchEntry.appendNext(deopt, bci);
+                        Goto end = new Goto(successor, null, false, graph);
+                        deopt.appendNext(end, bci);
+                        dispatchEntry.setEnd(end);
+                    }
+                    newBlocks.add(dispatchEntry);
+                    successor = dispatchEntry;
+                }
+            }
+
+            FrameState entryState = frameState.duplicateWithEmptyStack(bci);
+
+            BlockBegin entry = new BlockBegin(bci, ir.nextBlockNumber(), graph);
+            entry.setStateBefore(entryState);
+            ExceptionObject exception = new ExceptionObject(graph);
+            entry.appendNext(exception, bci);
+            FrameState stateWithException = entryState.duplicateModified(bci, CiKind.Void, exception);
+            BlockEnd end = new Goto(successor, stateWithException, false, graph);
+            exception.appendNext(end, bci);
+            entry.setEnd(end);
+
+            if (x instanceof Invoke) {
+                ((Invoke) x).setExceptionEdge(entry);
+            } else {
+                ((Throw) x).setExceptionEdge(entry);
+            }
+
+            updateDispatchChain(end.blockSuccessor(0), stateWithException, bci);
+        }
+    }
+
+    private void updateDispatchChain(BlockBegin dispatchEntry, FrameStateAccess state, int bci) {
+        FrameState oldState = dispatchEntry.stateBefore();
+        if (oldState != null && dispatchEntry.predecessors().size() == 1) {
+            dispatchEntry.setStateBefore(null);
+            oldState.delete();
+        }
+        dispatchEntry.mergeOrClone(state, null);
+        FrameState mergedState = dispatchEntry.stateBefore();
+
+        if (dispatchEntry.next() instanceof ExceptionDispatch) {
+            // ordinary dispatch handler
+            ExceptionDispatch dispatch = (ExceptionDispatch) dispatchEntry.next();
+            dispatch.setStateAfter(mergedState.duplicate(bci));
+            dispatch.setException(mergedState.stackAt(0));
+            dispatch.catchSuccessor().setStateBefore(mergedState.duplicate(bci));
+            updateDispatchChain(dispatch.otherSuccessor(), mergedState, bci);
+        } else if (dispatchEntry.next() instanceof Deoptimize) {
+            // deoptimizing handler
+            Deoptimize deopt = (Deoptimize) dispatchEntry.next();
+            deopt.setStateBefore(mergedState.duplicate(bci));
+            dispatchEntry.end().setStateAfter(mergedState.duplicate(bci));
+            updateDispatchChain(dispatchEntry.end().blockSuccessor(0), mergedState, bci);
+        } else if (dispatchEntry.next() instanceof Unwind) {
+            // unwind handler
+            Unwind unwind = (Unwind) dispatchEntry.next();
+            unwind.setStateAfter(mergedState.duplicate(bci));
+            unwind.setException(mergedState.stackAt(0));
+        } else {
+            // synchronization or default exception handler, nothing to do
+        }
     }
 
     /**
      * Adds an exception handler to the {@linkplain BlockBegin#exceptionHandlerBlocks() list}
      * of exception handlers for the {@link #curBlock current block}.
-     *
-     * @param exceptionHandlers
-     * @param handler
-     * @param curScopeData
-     * @param curState the current state with empty stack
-     * @param scopeCount
-     * @return {@code true} if handler catches all exceptions (i.e. {@code handler.isCatchAll() == true})
      */
-    private boolean addExceptionHandler(ArrayList<ExceptionHandler> exceptionHandlers, ExceptionHandler handler, FrameState curState) {
+    private ExceptionHandler addExceptionHandler(ExceptionHandler handler, FrameStateAccess curState) {
         compilation.setHasExceptionHandlers();
 
         BlockBegin entry = handler.entryBlock();
-        FrameState entryState = entry.stateBefore();
-
-        assert entry.bci() == handler.handler.handlerBCI();
-        assert entryState == null || curState.locksSize() == entryState.locksSize() : "locks do not match : cur:" + curState.locksSize() + " entry:" + entryState.locksSize();
-
-        // exception handler starts with an empty expression stack
-        curState = curState.duplicateWithEmptyStack();
-
-        entry.mergeOrClone(curState, method());
-
-        // add current state for correct handling of phi functions
-        int phiOperand = entry.addExceptionState(curState);
-
-        // add entry to the list of exception handlers of this block
-        curBlock.addExceptionHandler(entry);
-
-        newExceptionHandlers.add(entry);
 
         // clone exception handler
         ExceptionHandler newHandler = new ExceptionHandler(handler);
-        newHandler.setPhiOperand(phiOperand);
-        exceptionHandlers.add(newHandler);
 
         // fill in exception handler subgraph lazily
         if (!entry.wasVisited()) {
@@ -336,9 +411,7 @@
             //
             //   http://www.cs.arizona.edu/projects/sumatra/hallofshame/java-async-race.html
         }
-
-        // stop when reaching catch all
-        return handler.isCatchAll();
+        return newHandler;
     }
 
     private void genLoadConstant(int cpi) {
@@ -973,7 +1046,7 @@
 
         if (x instanceof Invoke || x instanceof Throw) {
             // connect the instruction to any exception handlers
-            x.setExceptionHandlers(handleException(x, bci));
+            handleException(x, bci);
         }
 
         return x;
@@ -1011,7 +1084,6 @@
         frameState.initializeFrom(syncHandler.stateBefore());
 
         int bci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
-        Value exception = appendWithoutOptimization(new ExceptionObject(graph), bci);
 
         assert lock != null;
         assert frameState.locksSize() > 0 && frameState.lockAt(frameState.locksSize() - 1) == lock;
@@ -1024,7 +1096,6 @@
         // exit the monitor
         genMonitorExit(lock, Instruction.SYNCHRONIZATION_ENTRY_BCI);
 
-        frameState.apush(exception);
         genThrow(bci);
         BlockEnd end = (BlockEnd) lastInstr;
         curBlock.setEnd(end);
@@ -1039,6 +1110,13 @@
     private void iterateAllBlocks() {
         BlockBegin b;
         while ((b = removeFromWorkList()) != null) {
+
+            // remove blocks that have no predecessors by the time it their bytecodes are parsed
+            if (b.blockPredecessors().size() == 0) {
+                b.setWasVisited(true);
+                continue;
+            }
+
             if (!b.wasVisited()) {
                 b.setWasVisited(true);
                 // now parse the block
@@ -1058,7 +1136,6 @@
 
         BlockBegin block = curBlock;
         BlockEnd end = null;
-        boolean pushException = block.isExceptionEntry() && block.next() == null;
         int prevBCI = bci;
         int endBCI = stream.endBCI();
         boolean blockStart = true;
@@ -1082,12 +1159,6 @@
             // read the opcode
             int opcode = stream.currentBC();
 
-            // push an exception object onto the stack if we are parsing an exception handler
-            if (pushException) {
-                frameState.apush(append(new ExceptionObject(graph)));
-                pushException = false;
-            }
-
             traceState();
             traceInstruction(bci, stream, opcode, blockStart);
             processBytecode(bci, stream, opcode);
@@ -1121,14 +1192,6 @@
         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.end());
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Wed May 18 18:09:20 2011 +0200
@@ -185,55 +185,16 @@
         // link predecessor to new block
         source.end().substituteSuccessor(target, newSucc);
 
-        // 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.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<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.end()) {
-                iterator.remove();
-                newSucc.addPredecessor(source.end());
-            }
-        }
         return newSucc;
     }
 
     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.end());
+        List<Instruction> predecessors = new ArrayList<Instruction>(oldBlock.blockPredecessors());
+        for (Instruction pred : predecessors) {
+            // substitute the new successor for this block in each predecessor
+            pred.block().end().substituteSuccessor(oldBlock, newBlock);
         }
-        for (BlockEnd pred : oldBlock.blockPredecessors()) {
-            // substitute the new successor for this block in each predecessor
-            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().successors().clear();
-    }
-
-    /**
-     * Disconnects the specified block from all other blocks.
-     * @param block the block to remove from the graph
-     */
-    public void disconnectFromGraph(BlockBegin block) {
-        for (BlockEnd p : block.blockPredecessors()) {
-            p.blockSuccessors().remove(block);
-        }
-        for (BlockBegin s : block.end().blockSuccessors()) {
-            s.blockPredecessors().remove(block);
-        }
+        oldBlock.end().clearSuccessors();
     }
 
     public int nextBlockNumber() {
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/BlockBegin.java	Wed May 18 18:09:20 2011 +0200
@@ -71,19 +71,7 @@
 
     public void setEnd(BlockEnd end) {
         assert end != null;
-        BlockEnd old = this.end();
-        if (old != end) {
-            if (old != null) {
-                // disconnect this block from its current successors
-                for (BlockBegin s : old.blockSuccessors()) {
-                    s.blockPredecessors().remove(this.end());
-                }
-            }
-            successors().set(super.successorCount() + SUCCESSOR_END, end);
-            for (BlockBegin s : end.blockSuccessors()) {
-                s.addPredecessor(end);
-            }
-        }
+        successors().set(super.successorCount() + SUCCESSOR_END, end);
     }
 
     private static final List<BlockBegin> NO_HANDLERS = Collections.emptyList();
@@ -93,7 +81,6 @@
      */
     public enum BlockFlag {
         StandardEntry,
-        ExceptionEntry,
         SubroutineEntry,
         BackwardBranchTarget,
         IsOnWorkList,
@@ -117,19 +104,12 @@
      */
     private int blockFlags;
 
-    /**
-     * The {@link BlockBegin} nodes for which this node is a successor.
-     */
-    private final List<BlockEnd> predecessors;
-
     private int depthFirstNumber;
     private int linearScanNumber;
     private int loopDepth;
     private int loopIndex;
 
     private BlockBegin dominator;
-    private List<BlockBegin> exceptionHandlerBlocks;
-    private List<FrameState> exceptionHandlerStates;
 
     // LIR block
     public LIRBlock lirBlock;
@@ -145,7 +125,6 @@
         this.blockID = blockID;
         depthFirstNumber = -1;
         linearScanNumber = -1;
-        predecessors = new ArrayList<BlockEnd>(2);
         loopIndex = -1;
         setBCI(bci);
     }
@@ -154,9 +133,13 @@
      * Gets the list of predecessors of this block.
      * @return the predecessor list
      */
-    public List<BlockEnd> blockPredecessors() {
-//      return Collections.unmodifiableList(predecessors);
-      return predecessors;
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public List<Instruction> blockPredecessors() {
+        if (predecessors().size() == 1 && predecessors().get(0) == graph().root()) {
+            return Collections.EMPTY_LIST;
+        } else {
+            return (List) Collections.unmodifiableList(predecessors());
+        }
     }
 
     /**
@@ -207,19 +190,6 @@
         return loopIndex;
     }
 
-    /**
-     * Gets the exception handlers that cover one or more instructions of this basic block.
-     *
-     * @return the exception handlers
-     */
-    public List<BlockBegin> exceptionHandlerBlocks() {
-        return exceptionHandlerBlocks == null ? NO_HANDLERS : exceptionHandlerBlocks;
-    }
-
-    public List<FrameState> exceptionHandlerStates() {
-        return exceptionHandlerStates;
-    }
-
     public void setDepthFirstNumber(int depthFirstNumber) {
         assert depthFirstNumber >= 0;
         this.depthFirstNumber = depthFirstNumber;
@@ -288,10 +258,27 @@
         BlockBegin block;
         while ((block = queue.poll()) != null) {
             closure.apply(block);
-            queueBlocks(queue, block.exceptionHandlerBlocks(), mark);
+
+            Instruction inst = block;
+            ArrayList<BlockBegin> excBlocks = new ArrayList<BlockBegin>();
+            while (inst != null) {
+                if (inst instanceof Invoke) {
+                    excBlocks.add(((Invoke) inst).exceptionEdge());
+                } else if (inst instanceof Throw) {
+                    excBlocks.add(((Throw) inst).exceptionEdge());
+                }
+                inst = inst.next();
+            }
+            while (excBlocks.remove(null)) {
+                // nothing
+            }
+            if (excBlocks.size() > 0) {
+                queueBlocks(queue, excBlocks, mark);
+            }
+
             queueBlocks(queue, block.end().blockSuccessors(), mark);
             if (predecessors) {
-                queueBlockEnds(queue, block.predecessors, mark);
+                queueBlockEnds(queue, block.blockPredecessors(), mark);
             }
         }
     }
@@ -307,10 +294,10 @@
         }
     }
 
-    private void queueBlockEnds(LinkedList<BlockBegin> queue, List<BlockEnd> list, IdentityHashMap<BlockBegin, BlockBegin> mark) {
+    private void queueBlockEnds(LinkedList<BlockBegin> queue, List<Instruction> list, IdentityHashMap<BlockBegin, BlockBegin> mark) {
         if (list != null) {
-            for (BlockEnd end : list) {
-                BlockBegin b = end.begin();
+            for (Instruction end : list) {
+                BlockBegin b = end.block();
                 if (!mark.containsKey(b)) {
                     queue.offer(b);
                     mark.put(b, b);
@@ -324,9 +311,27 @@
             mark.put(this, this);
             closure.apply(this);
             BlockEnd e = end();
-            if (exceptionHandlerBlocks != null) {
-                iterateReverse(mark, closure, exceptionHandlerBlocks);
+
+            Instruction inst = this;
+            ArrayList<BlockBegin> excBlocks = new ArrayList<BlockBegin>();
+            while (inst != null) {
+                if (inst instanceof Invoke) {
+                    excBlocks.add(((Invoke) inst).exceptionEdge());
+                } else if (inst instanceof Throw) {
+                    excBlocks.add(((Throw) inst).exceptionEdge());
+                }
+                inst = inst.next();
             }
+            while (excBlocks.remove(null)) {
+                // nothing
+            }
+            if (excBlocks.size() > 0) {
+                iterateReverse(mark, closure, excBlocks);
+            }
+
+//            if (exceptionHandlerBlocks != null) {
+//                iterateReverse(mark, closure, exceptionHandlerBlocks);
+//            }
             assert e != null : "block must have block end";
             iterateReverse(mark, closure, e.blockSuccessors());
         }
@@ -338,58 +343,6 @@
         }
     }
 
-    /**
-     * Adds an exception handler that covers one or more instructions in this block.
-     *
-     * @param handler the entry block for the exception handler to add
-     */
-    public void addExceptionHandler(BlockBegin handler) {
-        assert handler != null && handler.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry);
-        if (exceptionHandlerBlocks == null) {
-            exceptionHandlerBlocks = new ArrayList<BlockBegin>(3);
-            exceptionHandlerBlocks.add(handler);
-        } else if (!exceptionHandlerBlocks.contains(handler)) {
-            exceptionHandlerBlocks.add(handler);
-        }
-    }
-
-    /**
-     * Adds a frame state that merges into the exception handler whose entry is this block.
-     *
-     * @param state the frame state at an instruction that raises an exception that can be caught by the exception
-     *            handler represented by this block
-     * @return the index of {@code state} in the list of frame states merging at this block (i.e. the frames states for
-     *         all instruction throwing an exception caught by this exception handler)
-     */
-    public int addExceptionState(FrameState state) {
-        assert checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry);
-        if (exceptionHandlerStates == null) {
-            exceptionHandlerStates = new ArrayList<FrameState>(4);
-        }
-        exceptionHandlerStates.add(state);
-        return exceptionHandlerStates.size() - 1;
-    }
-
-    /**
-     * Add a predecessor to this block.
-     * @param pred the predecessor to add
-     */
-    public void addPredecessor(BlockEnd pred) {
-        assert pred != null;
-        predecessors.add(pred);
-    }
-
-    /**
-     * Removes all occurrences of the specified block from the predecessor list of this block.
-     * @param pred the predecessor to remove
-     */
-    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
-        }
-    }
-
     @Override
     public void accept(ValueVisitor v) {
         v.visitBlockBegin(this);
@@ -409,7 +362,7 @@
             FrameState duplicate = newState.duplicate(bci());
             assert duplicate.bci == bci() : "duplicate.bci=" + duplicate.bci + " my bci=" + bci();
 
-            if (C1XOptions.UseStackMapTableLiveness) {
+            if (C1XOptions.UseStackMapTableLiveness && method != null) {
                 // if a liveness map is available, use it to invalidate dead locals
                 CiBitMap[] livenessMap = method.livenessMap();
                 if (livenessMap != null && bci() >= 0) {
@@ -489,14 +442,6 @@
         setBlockFlag(BlockFlag.CriticalEdgeSplit, value);
     }
 
-    public boolean isExceptionEntry() {
-        return checkBlockFlag(BlockFlag.ExceptionEntry);
-    }
-
-    public void setExceptionEntry() {
-        setBlockFlag(BlockFlag.ExceptionEntry);
-    }
-
     public boolean isSubroutineEntry() {
         return checkBlockFlag(BlockFlag.SubroutineEntry);
     }
@@ -556,7 +501,6 @@
     public void copyBlockFlags(BlockBegin other) {
         copyBlockFlag(other, BlockBegin.BlockFlag.ParserLoopHeader);
         copyBlockFlag(other, BlockBegin.BlockFlag.SubroutineEntry);
-        copyBlockFlag(other, BlockBegin.BlockFlag.ExceptionEntry);
         copyBlockFlag(other, BlockBegin.BlockFlag.WasVisited);
     }
 
@@ -619,8 +563,12 @@
      * @return the number of predecessors
      */
     public int numberOfPreds() {
-//        assert predecessors.size() == predecessors().size();
-        return predecessors.size();
+        // ignore the graph root
+        if (predecessors().size() == 1 && predecessors().get(0) == graph().root()) {
+            return 0;
+        } else {
+            return predecessors().size();
+        }
     }
 
     /**
@@ -645,25 +593,16 @@
         return lirBlock;
     }
 
-    public int exceptionHandlerPco() {
-        return lirBlock == null ? 0 : lirBlock.exceptionHandlerPCO;
+    public int blockEntryPco() {
+        return lirBlock == null ? 0 : lirBlock.blockEntryPco;
     }
 
-    public void setExceptionHandlerPco(int codeOffset) {
-        lirBlock().exceptionHandlerPCO = codeOffset;
+    public void setBlockEntryPco(int codeOffset) {
+        lirBlock().blockEntryPco = codeOffset;
     }
 
-    public int numberOfExceptionHandlers() {
-        return exceptionHandlerBlocks == null ? 0 : exceptionHandlerBlocks.size();
-    }
-
-    public BlockBegin exceptionHandlerAt(int i) {
-        return exceptionHandlerBlocks.get(i);
-    }
-
-    public BlockEnd predAt(int j) {
-//        assert predecessors.get(j) == predecessors().get(j);
-        return predecessors.get(j);
+    public Instruction predAt(int j) {
+        return (Instruction) predecessors().get(j);
     }
 
     public int firstLirInstructionId() {
@@ -682,9 +621,8 @@
         lirBlock.lastLirInstructionID = lastLirInstructionId;
     }
 
-    public boolean isPredecessor(BlockEnd block) {
-//        assert predecessors.contains(block) == predecessors().contains(block);
-        return predecessors.contains(block);
+    public boolean isPredecessor(Instruction block) {
+        return predecessors().contains(block);
     }
 
     public void printWithoutPhis(LogStream out) {
@@ -694,9 +632,6 @@
 
         // print flags
         StringBuilder sb = new StringBuilder(8);
-        if (isExceptionEntry()) {
-            sb.append('E');
-        }
         if (isSubroutineEntry()) {
             sb.append('s');
         }
@@ -723,14 +658,6 @@
                 out.print(" B").print(successor.blockID);
             }
         }
-        // print exception handlers
-        if (!exceptionHandlers().isEmpty()) {
-            out.print(" (xhandlers");
-            for (BlockBegin handler : exceptionHandlerBlocks()) {
-                out.print(" B").print(handler.blockID);
-            }
-            out.print(')');
-        }
 
         // print dominator block
         if (dominator() != null) {
@@ -740,8 +667,8 @@
         // print predecessors
         if (!blockPredecessors().isEmpty()) {
             out.print(" pred:");
-            for (BlockEnd pred : blockPredecessors()) {
-                out.print(" B").print(pred.begin().blockID);
+            for (Instruction pred : blockPredecessors()) {
+                out.print(" B").print(pred.block().blockID);
             }
         }
     }
@@ -874,5 +801,34 @@
         return "BlockBegin #" + blockID;
     }
 
+    /**
+     * Iterates over all successors of this block: successors of the end node and exception handler.
+     */
+    public void allSuccessorsDo(boolean backwards, BlockClosure closure) {
+        if (backwards) {
+            for (int i = numberOfSux() - 1; i >= 0; i--) {
+                closure.apply(suxAt(i));
+            }
+        } else {
+            for (int i = 0; i < numberOfSux(); i++) {
+                closure.apply(suxAt(i));
+            }
+        }
+        for (Instruction x = next(); x != null; x = x.next()) {
+            if (x instanceof Invoke && ((Invoke) x).exceptionEdge() != null) {
+                closure.apply(((Invoke) x).exceptionEdge());
+            } else if (x instanceof Throw && ((Throw) x).exceptionEdge() != null) {
+                closure.apply(((Throw) x).exceptionEdge());
+            }
+        }
+    }
+
+    public void verifyPredecessors() {
+        for (int i = 0; i < numberOfPreds(); i++) {
+            predAt(i);
+        }
+
+    }
+
 
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/BlockEnd.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/BlockEnd.java	Wed May 18 18:09:20 2011 +0200
@@ -181,10 +181,16 @@
      * Gets this block end's list of successors.
      * @return the successor list
      */
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({ "unchecked", "rawtypes"})
     public List<BlockBegin> blockSuccessors() {
         List<BlockBegin> list = (List) successors().subList(super.successorCount() + SUCCESSOR_COUNT, super.successorCount() + blockSuccessorCount + SUCCESSOR_COUNT);
         return Collections.unmodifiableList(list);
     }
 
+    public void clearSuccessors() {
+        for (int i = 0; i < blockSuccessorCount(); i++) {
+            setBlockSuccessor(i, null);
+        }
+    }
+
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/ComputeLinearScanOrder.java	Wed May 18 18:09:20 2011 +0200
@@ -140,7 +140,7 @@
      * 3. Number loop header blocks.
      * 4. Create a list with all loop end blocks.
      */
-    private void countEdges(BlockBegin cur, BlockBegin parent) {
+    private void countEdges(final BlockBegin cur, BlockBegin parent) {
         if (C1XOptions.TraceLinearScanLevel >= 3) {
             TTY.println("Counting edges for block B%d%s", cur.blockID, parent == null ? "" : " coming from B" + parent.blockID);
         }
@@ -158,15 +158,6 @@
 
             parent.setBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd);
 
-            // When a loop header is also the start of an exception handler, then the backward branch is
-            // an exception edge. Because such edges are usually critical edges which cannot be split, the
-            // loop must be excluded here from processing.
-            if (cur.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry)) {
-                // Make sure that dominators are correct in this weird situation
-                iterativeDominators = true;
-                return;
-            }
-
             loopEndBlocks.add(parent);
             return;
         }
@@ -186,13 +177,11 @@
         setActive(cur);
 
         // recursive call for all successors
-        int i;
-        for (i = cur.numberOfSux() - 1; i >= 0; i--) {
-            countEdges(cur.suxAt(i), cur);
-        }
-        for (i = cur.numberOfExceptionHandlers() - 1; i >= 0; i--) {
-            countEdges(cur.exceptionHandlerAt(i), cur);
-        }
+        cur.allSuccessorsDo(true, new BlockClosure() {
+            public void apply(BlockBegin block) {
+                countEdges(block, cur);
+            }
+        });
 
         clearActive(cur);
 
@@ -250,7 +239,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).begin();
+                        BlockBegin pred = cur.predAt(j).block();
 
                         if (!isBlockInLoop(loopIdx, pred)) {
                             // this predecessor has not been processed yet, so add it to work list
@@ -319,12 +308,11 @@
                 cur.setLoopIndex(minLoopIdx);
 
                 // append all unvisited successors to work list
-                for (i = cur.numberOfSux() - 1; i >= 0; i--) {
-                    workList.add(cur.suxAt(i));
-                }
-                for (i = cur.numberOfExceptionHandlers() - 1; i >= 0; i--) {
-                    workList.add(cur.exceptionHandlerAt(i));
-                }
+                cur.allSuccessorsDo(true, new BlockClosure() {
+                    public void apply(BlockBegin block) {
+                        workList.add(block);
+                    }
+                });
             }
         } while (!workList.isEmpty());
     }
@@ -352,12 +340,7 @@
             if (C1XOptions.TraceLinearScanLevel >= 4) {
                 TTY.println("DOM: initializing dominator of B%d to B%d", cur.blockID, parent.blockID);
             }
-            if (cur.isExceptionEntry()) {
-                assert parent.dominator() != null;
-                cur.setDominator(parent.dominator());
-            } else {
-                cur.setDominator(parent);
-            }
+            cur.setDominator(parent);
 
         } else if (!(cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) && parent.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd))) {
             if (C1XOptions.TraceLinearScanLevel >= 4) {
@@ -412,10 +395,10 @@
         }
         curBit--;
 
-        // exceptions handlers are added as late as possible
-        if (!cur.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry)) {
-            weight |= (1 << curBit);
-        }
+//        // exceptions handlers are added as late as possible
+//        if (!cur.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry)) {
+//            weight |= (1 << curBit);
+//        }
         curBit--;
 
         // guarantee that weight is > 0
@@ -505,27 +488,17 @@
         }
 
         do {
-            BlockBegin cur = workList.remove(workList.size() - 1);
+            final BlockBegin cur = workList.remove(workList.size() - 1);
             appendBlock(cur);
 
-            int i;
-            int numSux = cur.numberOfSux();
-            // changed loop order to get "intuitive" order of if- and else-blocks
-            for (i = 0; i < numSux; i++) {
-                BlockBegin sux = cur.suxAt(i);
-                computeDominator(sux, cur);
-                if (readyForProcessing(sux)) {
-                    sortIntoWorkList(sux);
+            cur.allSuccessorsDo(false, new BlockClosure() {
+                public void apply(BlockBegin block) {
+                    computeDominator(block, cur);
+                    if (readyForProcessing(block)) {
+                        sortIntoWorkList(block);
+                    }
                 }
-            }
-            numSux = cur.numberOfExceptionHandlers();
-            for (i = 0; i < numSux; i++) {
-                BlockBegin sux = cur.exceptionHandlerAt(i);
-                computeDominator(sux, cur);
-                if (readyForProcessing(sux)) {
-                    sortIntoWorkList(sux);
-                }
-            }
+            });
         } while (workList.size() > 0);
     }
 
@@ -539,17 +512,11 @@
             BlockBegin block = linearScanOrder.get(i);
 
             assert block.numberOfPreds() > 0;
-            BlockBegin dominator = block.predAt(0).begin();
-            if (block.isExceptionEntry()) {
-                dominator = dominator.dominator();
-            }
+            BlockBegin dominator = block.predAt(0).block();
 
             int numPreds = block.numberOfPreds();
             for (int j = 1; j < numPreds; j++) {
-                BlockBegin curPred = block.predAt(j).begin();
-                if (block.isExceptionEntry()) {
-                    curPred = curPred.dominator();
-                }
+                BlockBegin curPred = block.predAt(j).block();
                 dominator = commonDominator(dominator, curPred);
             }
 
@@ -601,7 +568,6 @@
             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.isExceptionEntry() ? " ex" : "   ");
                 TTY.print(cur.isCriticalEdgeSplit() ? " ce" : "   ");
                 TTY.print(cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader) ? " lh" : "   ");
                 TTY.print(cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopEnd) ? " le" : "   ");
@@ -615,7 +581,7 @@
                 if (cur.numberOfPreds() > 0) {
                     TTY.print("    preds: ");
                     for (int j = 0; j < cur.numberOfPreds(); j++) {
-                        BlockBegin pred = cur.predAt(j).begin();
+                        BlockBegin pred = cur.predAt(j).block();
                         TTY.print("B%d ", pred.blockID);
                     }
                 }
@@ -626,13 +592,6 @@
                         TTY.print("B%d ", sux.blockID);
                     }
                 }
-                if (cur.numberOfExceptionHandlers() > 0) {
-                    TTY.print("    ex: ");
-                    for (int j = 0; j < cur.numberOfExceptionHandlers(); j++) {
-                        BlockBegin ex = cur.exceptionHandlerAt(j);
-                        TTY.print("B%d ", ex.blockID);
-                    }
-                }
                 TTY.println();
             }
         }
@@ -666,8 +625,8 @@
                 }
             }
 
-            for (BlockEnd pred : cur.blockPredecessors()) {
-                BlockBegin begin = pred.begin();
+            for (Instruction pred : cur.blockPredecessors()) {
+                BlockBegin begin = pred.block();
                 assert begin.linearScanNumber() >= 0 && begin.linearScanNumber() == linearScanOrder.indexOf(begin) : "incorrect linearScanNumber";
                 if (!cur.checkBlockFlag(BlockBegin.BlockFlag.LinearScanLoopHeader)) {
                     assert cur.linearScanNumber() > begin.linearScanNumber() : "invalid order";
@@ -685,7 +644,7 @@
             } else {
                 assert cur.dominator() != null : "all but first block must have dominator";
             }
-            assert cur.numberOfPreds() != 1 || cur.dominator() == cur.predAt(0).begin() || cur.isExceptionEntry() : "Single predecessor must also be dominator";
+            assert cur.numberOfPreds() != 1 || cur.dominator() == cur.predAt(0).block() : "Single predecessor must also be dominator";
         }
 
         // check that all loops are continuous
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/ExceptionDispatch.java	Wed May 18 18:09:20 2011 +0200
@@ -0,0 +1,143 @@
+/*
+ * 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.ir;
+
+import com.oracle.graal.graph.*;
+import com.sun.c1x.debug.*;
+import com.sun.c1x.value.*;
+import com.sun.cri.ci.*;
+
+/**
+ * This instruction takes an exception object and has two successors:
+ * The catchSuccessor is called whenever the exception matches the given type, otherwise otherSuccessor is called.
+ */
+public final class ExceptionDispatch extends BlockEnd {
+
+    private static final int INPUT_COUNT = 1;
+    private static final int INPUT_EXCEPTION = 0;
+
+    private static final int SUCCESSOR_COUNT = 0;
+
+    @Override
+    protected int inputCount() {
+        return super.inputCount() + INPUT_COUNT;
+    }
+
+    @Override
+    protected int successorCount() {
+        return super.successorCount() + SUCCESSOR_COUNT;
+    }
+
+    /**
+     * The instruction producing the exception object.
+     */
+     public Value exception() {
+        return (Value) inputs().get(super.inputCount() + INPUT_EXCEPTION);
+    }
+
+    public Value setException(Value n) {
+        return (Value) inputs().set(super.inputCount() + INPUT_EXCEPTION, n);
+    }
+
+    private final ExceptionHandler handler;
+
+    /**
+     * Constructs a new ExceptionDispatch instruction.
+     */
+    public ExceptionDispatch(Value exception, BlockBegin catchSuccessor, BlockBegin otherSuccessor, ExceptionHandler handler, FrameState stateAfter, boolean isSafepoint, Graph graph) {
+        super(CiKind.Int, stateAfter, isSafepoint, 2, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        setException(exception);
+        setBlockSuccessor(0, otherSuccessor);
+        setBlockSuccessor(1, catchSuccessor);
+        this.handler = handler;
+    }
+
+    public ExceptionHandler handler() {
+        return handler;
+    }
+
+    /**
+     * Gets the block corresponding to the catch block.
+     * @return the true successor
+     */
+    public BlockBegin catchSuccessor() {
+        return blockSuccessor(1);
+    }
+
+    /**
+     * Gets the block corresponding to the rest of the dispatch chain.
+     * @return the false successor
+     */
+    public BlockBegin otherSuccessor() {
+        return blockSuccessor(0);
+    }
+
+    /**
+     * Gets the block corresponding to the specified outcome of the branch.
+     * @param istrue {@code true} if the true successor is requested, {@code false} otherwise
+     * @return the corresponding successor
+     */
+    public BlockBegin successor(boolean istrue) {
+        return blockSuccessor(istrue ? 1 : 0);
+    }
+
+    /**
+     * Swaps the successor blocks to this if and negates the condition (e.g. == goes to !=)
+     * @see Condition#negate()
+     */
+    public void swapSuccessors() {
+        BlockBegin t = blockSuccessor(0);
+        BlockBegin f = blockSuccessor(1);
+        setBlockSuccessor(0, f);
+        setBlockSuccessor(1, t);
+    }
+
+    @Override
+    public void accept(ValueVisitor v) {
+        v.visitExceptionDispatch(this);
+    }
+
+    @Override
+    public void print(LogStream out) {
+        out.print("exception_dispatch ").
+        print(exception()).
+        print(' ').
+        print("instanceof").
+        print(' ').
+        print(handler.handler.catchType().name()).
+        print(" then B").
+        print(blockSuccessors().get(1).blockID).
+        print(" else B").
+        print(blockSuccessors().get(0).blockID);
+        if (isSafepoint()) {
+            out.print(" (safepoint)");
+        }
+    }
+
+    @Override
+    public String shortName() {
+        return "Dispatch " + handler.handler.catchType().name();
+    }
+
+
+}
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Instruction.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Instruction.java	Wed May 18 18:09:20 2011 +0200
@@ -79,11 +79,6 @@
      */
     private int bci;
 
-    /**
-     * List of associated exception handlers.
-     */
-    private List<ExceptionHandler> exceptionHandlers = ExceptionHandler.ZERO_HANDLERS;
-
     private boolean isAppended = false;
 
     /**
@@ -185,22 +180,6 @@
     }
 
     /**
-     * Gets the list of exception handlers associated with this instruction.
-     * @return the list of exception handlers for this instruction
-     */
-    public final List<ExceptionHandler> exceptionHandlers() {
-        return exceptionHandlers;
-    }
-
-    /**
-     * Sets the list of exception handlers for this instruction.
-     * @param exceptionHandlers the exception handlers
-     */
-    public final void setExceptionHandlers(List<ExceptionHandler> exceptionHandlers) {
-        this.exceptionHandlers = exceptionHandlers;
-    }
-
-    /**
      * Compute the value number of this Instruction. Local and global value numbering
      * optimizations use a hash map, and the value number provides a hash code.
      * If the instruction cannot be value numbered, then this method should return
@@ -247,4 +226,8 @@
     public FrameState stateAfter() {
         return null;
     }
+
+    public BlockBegin exceptionEdge() {
+        return null;
+    }
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Invoke.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Invoke.java	Wed May 18 18:09:20 2011 +0200
@@ -36,7 +36,8 @@
 
     private final int argumentCount;
 
-    private static final int SUCCESSOR_COUNT = 0;
+    private static final int SUCCESSOR_COUNT = 1;
+    private static final int SUCCESSOR_EXCEPTION_EDGE = 0;
 
     @Override
     protected int inputCount() {
@@ -65,6 +66,18 @@
         return argumentCount;
     }
 
+    /**
+     * The entry to the exception dispatch chain for this invoke.
+     */
+    @Override
+    public BlockBegin exceptionEdge() {
+        return (BlockBegin) successors().get(super.successorCount() + SUCCESSOR_EXCEPTION_EDGE);
+    }
+
+    public BlockBegin setExceptionEdge(BlockBegin n) {
+        return (BlockBegin) successors().set(super.successorCount() + SUCCESSOR_EXCEPTION_EDGE, n);
+    }
+
     public final int opcode;
     public final RiMethod target;
     public final RiType returnType;
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java	Wed May 18 18:09:20 2011 +0200
@@ -116,13 +116,7 @@
      * @return the instruction that produced the value in the i'th predecessor
      */
     public Value inputAt(int i) {
-        FrameState state;
-        if (block().isExceptionEntry()) {
-            state = block().exceptionHandlerStates().get(i);
-        } else {
-            state = block().blockPredecessors().get(i).stateAfter();
-        }
-        return inputIn(state);
+        return inputIn(block().blockPredecessors().get(i).stateAfter());
     }
 
     /**
@@ -143,11 +137,7 @@
      * @return the number of inputs in this phi
      */
     public int phiInputCount() {
-        if (block().isExceptionEntry()) {
-            return block().exceptionHandlerStates().size();
-        } else {
-            return block().blockPredecessors().size();
-        }
+        return block().blockPredecessors().size();
     }
 
     @Override
@@ -170,7 +160,7 @@
 
     @Override
     public String shortName() {
-        return "Phi: " + index;
+        return "Phi: " + index + " (" + phiInputCount() + ")";
     }
 
 
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/StateSplit.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/StateSplit.java	Wed May 18 18:09:20 2011 +0200
@@ -32,11 +32,11 @@
  */
 public abstract class StateSplit extends Instruction {
 
-    private static final int INPUT_COUNT = 2;
-    private static final int INPUT_STATE_AFTER = 0;
-    private static final int INPUT_STATE_BEFORE = 1;
+    private static final int INPUT_COUNT = 1;
+    private static final int INPUT_STATE_BEFORE = 0;
 
-    private static final int SUCCESSOR_COUNT = 0;
+    private static final int SUCCESSOR_COUNT = 1;
+    private static final int SUCCESSOR_STATE_AFTER = 0;
 
     @Override
     protected int inputCount() {
@@ -51,22 +51,6 @@
     /**
      * The state for this instruction.
      */
-     @Override
-    public FrameState stateAfter() {
-        return (FrameState) inputs().get(super.inputCount() + INPUT_STATE_AFTER);
-    }
-
-    public FrameState setStateAfter(FrameState n) {
-        if (n != null && this instanceof BlockBegin) {
-            Exception e = new Exception();
-            e.printStackTrace();
-        }
-        return (FrameState) inputs().set(super.inputCount() + INPUT_STATE_AFTER, n);
-    }
-
-    /**
-     * The state for this instruction.
-     */
     public FrameState stateBefore() {
         return (FrameState) inputs().get(super.inputCount() + INPUT_STATE_BEFORE);
     }
@@ -76,6 +60,18 @@
     }
 
     /**
+     * The state for this instruction.
+     */
+     @Override
+    public FrameState stateAfter() {
+        return (FrameState) successors().get(super.successorCount() + SUCCESSOR_STATE_AFTER);
+    }
+
+    public FrameState setStateAfter(FrameState n) {
+        return (FrameState) successors().set(super.successorCount() + SUCCESSOR_STATE_AFTER, n);
+    }
+
+    /**
      * Creates a new state split with the specified value type.
      * @param kind the type of the value that this instruction produces
      * @param inputCount
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Throw.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Throw.java	Wed May 18 18:09:20 2011 +0200
@@ -36,7 +36,8 @@
     private static final int INPUT_EXCEPTION = 0;
     private static final int INPUT_STATE_BEFORE = 1;
 
-    private static final int SUCCESSOR_COUNT = 0;
+    private static final int SUCCESSOR_COUNT = 1;
+    private static final int SUCCESSOR_EXCEPTION_EDGE = 0;
 
     @Override
     protected int inputCount() {
@@ -71,6 +72,19 @@
     }
 
     /**
+     * The entry to the exception dispatch chain for this throw.
+     * TODO ls: this needs more cleanup - throw should either unwind or jump to the exception dispatch chain
+     */
+    @Override
+    public BlockBegin exceptionEdge() {
+        return (BlockBegin) successors().get(super.successorCount() + SUCCESSOR_EXCEPTION_EDGE);
+    }
+
+    public BlockBegin setExceptionEdge(BlockBegin n) {
+        return (BlockBegin) successors().set(super.successorCount() + SUCCESSOR_EXCEPTION_EDGE, n);
+    }
+
+    /**
      * Creates a new Throw instruction.
      * @param exception the instruction that generates the exception to throw
      * @param stateAfter the state before the exception is thrown but after the exception object has been popped
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Unwind.java	Wed May 18 18:09:20 2011 +0200
@@ -0,0 +1,75 @@
+/*
+ * 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.ir;
+
+import com.oracle.graal.graph.*;
+import com.sun.c1x.debug.*;
+import com.sun.cri.ci.*;
+
+/**
+ * Unwind takes an exception object, destroys the current stack frame and passes the exception object to the system's exception dispatch code.
+ */
+public final class Unwind extends BlockEnd {
+
+    private static final int INPUT_COUNT = 1;
+    private static final int INPUT_EXCEPTION = 0;
+
+    private static final int SUCCESSOR_COUNT = 0;
+
+    @Override
+    protected int inputCount() {
+        return super.inputCount() + INPUT_COUNT;
+    }
+
+    @Override
+    protected int successorCount() {
+        return super.successorCount() + SUCCESSOR_COUNT;
+    }
+
+    /**
+     * The instruction that produces the exception object.
+     */
+     public Value exception() {
+        return (Value) inputs().get(super.inputCount() + INPUT_EXCEPTION);
+    }
+
+    public Value setException(Value n) {
+        assert n == null || n.kind == CiKind.Object;
+        return (Value) inputs().set(super.inputCount() + INPUT_EXCEPTION, n);
+    }
+
+    public Unwind(Value exception, boolean isSafepoint, Graph graph) {
+        super(CiKind.Object, null, isSafepoint, 0, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        setException(exception);
+    }
+
+    @Override
+    public void accept(ValueVisitor v) {
+        v.visitUnwind(this);
+    }
+
+    @Override
+    public void print(LogStream out) {
+        out.print(kind.typeChar).print("unwind ").print(exception());
+    }
+}
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/ValueVisitor.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/ValueVisitor.java	Wed May 18 18:09:20 2011 +0200
@@ -68,4 +68,6 @@
     public abstract void visitTableSwitch(TableSwitch i);
     public abstract void visitThrow(Throw i);
     public abstract void visitDeoptimize(Deoptimize deoptimize);
+    public abstract void visitExceptionDispatch(ExceptionDispatch exceptionDispatch);
+    public abstract void visitUnwind(Unwind unwind);
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRAssembler.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIRAssembler.java	Wed May 18 18:09:20 2011 +0200
@@ -96,35 +96,6 @@
 
     public abstract void emitTraps();
 
-    public void emitExceptionEntries() {
-        if (tasm.exceptionInfoList == null) {
-            return;
-        }
-        for (ExceptionInfo ilist : tasm.exceptionInfoList) {
-            List<ExceptionHandler> handlers = ilist.exceptionHandlers;
-
-            for (ExceptionHandler handler : handlers) {
-                assert handler.lirOpId() != -1 : "handler not processed by LinearScan";
-                assert handler.entryCode() == null || handler.entryCode().instructionsList().get(handler.entryCode().instructionsList().size() - 1).code == LIROpcode.Branch : "last operation must be branch";
-
-                if (handler.entryCodeOffset() == -1) {
-                    // entry code not emitted yet
-                    if (handler.entryCode() != null && handler.entryCode().instructionsList().size() > 1) {
-                        handler.setEntryCodeOffset(codePos());
-                        if (C1XOptions.CommentedAssembly) {
-                            tasm.blockComment("Exception adapter block");
-                        }
-                        emitLirList(handler.entryCode());
-                    } else {
-                        handler.setEntryCodeOffset(handler.entryBlock().exceptionHandlerPco());
-                    }
-
-                    assert handler.entryCodeOffset() != -1 : "must be set now";
-                }
-            }
-        }
-    }
-
     public void emitCode(List<BlockBegin> hir) {
         if (C1XOptions.PrintLIR && !TTY.isSuppressed()) {
             LIRList.printLIR(hir);
@@ -142,12 +113,7 @@
             emitAlignment();
         }
 
-        // if this block is the start of an exception handler, record the
-        // PC offset of the first instruction for later construction of
-        // the ExceptionHandlerTable
-        if (block.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry)) {
-            block.setExceptionHandlerPco(codePos());
-        }
+        block.setBlockEntryPco(codePos());
 
         if (C1XOptions.PrintLIRWithAssembly) {
             block.printWithoutPhis(TTY.out());
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRBlock.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIRBlock.java	Wed May 18 18:09:20 2011 +0200
@@ -28,8 +28,6 @@
 
 /**
  * The {@code LIRBlock} class definition.
- *
- * @author Ben L. Titzer
  */
 public final class LIRBlock {
 
@@ -70,7 +68,7 @@
 
     public int firstLirInstructionID;
     public int lastLirInstructionID;
-    public int exceptionHandlerPCO;
+    public int blockEntryPco;
 
     public LIRList lir() {
         return lir;
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRDebugInfo.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIRDebugInfo.java	Wed May 18 18:09:20 2011 +0200
@@ -31,10 +31,6 @@
 
 /**
  * This class represents debugging and deoptimization information attached to a LIR instruction.
- *
- * @author Marcelo Cintra
- * @author Thomas Wuerthinger
- * @author Ben L. Titzer
  */
 public class LIRDebugInfo {
 
@@ -43,27 +39,18 @@
     }
 
     public final FrameState state;
-    public final List<ExceptionHandler> exceptionHandlers;
+    public final BlockBegin exceptionEdge;
     public CiDebugInfo debugInfo;
 
-    public LIRDebugInfo(FrameState state, List<ExceptionHandler> exceptionHandlers) {
+    public LIRDebugInfo(FrameState state, BlockBegin exceptionEdge) {
         assert state != null;
         this.state = state;
-        this.exceptionHandlers = exceptionHandlers;
+        this.exceptionEdge = exceptionEdge;
     }
 
     private LIRDebugInfo(LIRDebugInfo info) {
         this.state = info.state;
-
-        // deep copy of exception handlers
-        if (info.exceptionHandlers != null) {
-            this.exceptionHandlers = new ArrayList<ExceptionHandler>(info.exceptionHandlers.size());
-            for (ExceptionHandler h : info.exceptionHandlers) {
-                this.exceptionHandlers.add(new ExceptionHandler(h));
-            }
-        } else {
-            this.exceptionHandlers = null;
-        }
+        this.exceptionEdge = info.exceptionEdge;
     }
 
     public LIRDebugInfo copy() {
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRInstruction.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIRInstruction.java	Wed May 18 18:09:20 2011 +0200
@@ -483,12 +483,8 @@
         }
     }
 
-    public final List<ExceptionHandler> exceptionEdges() {
-        if (info != null && info.exceptionHandlers != null) {
-            return info.exceptionHandlers;
-        }
-
-        return Collections.emptyList();
+    public final BlockBegin exceptionEdge() {
+        return info.exceptionEdge;
     }
 
     @Override
--- a/graal/GraalCompiler/src/com/sun/c1x/lir/LIRList.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/lir/LIRList.java	Wed May 18 18:09:20 2011 +0200
@@ -411,9 +411,6 @@
         TTY.print("B%d ", x.blockID);
 
         // print flags
-        if (x.checkBlockFlag(BlockBegin.BlockFlag.ExceptionEntry)) {
-            TTY.print("ex ");
-        }
         if (x.checkBlockFlag(BlockBegin.BlockFlag.SubroutineEntry)) {
             TTY.print("jsr ");
         }
@@ -434,7 +431,7 @@
         if (x.numberOfPreds() > 0) {
             TTY.print("preds: ");
             for (int i = 0; i < x.numberOfPreds(); i++) {
-                TTY.print("B%d ", x.predAt(i).begin().blockID);
+                TTY.print("B%d ", x.predAt(i).block().blockID);
             }
         }
 
@@ -445,14 +442,6 @@
             }
         }
 
-        // print exception handlers
-        if (x.numberOfExceptionHandlers() > 0) {
-            TTY.print("xhandler: ");
-            for (int i = 0; i < x.numberOfExceptionHandlers(); i++) {
-                TTY.print("B%d ", x.exceptionHandlerAt(i).blockID);
-            }
-        }
-
         TTY.println();
     }
 
--- a/graal/GraalCompiler/src/com/sun/c1x/opt/InstructionSubstituter.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/opt/InstructionSubstituter.java	Wed May 18 18:09:20 2011 +0200
@@ -42,11 +42,6 @@
 
     public void apply(BlockBegin block) {
         Instruction last = null;
-        if (block.exceptionHandlerStates() != null) {
-            for (FrameState s : block.exceptionHandlerStates()) {
-                s.inputValuesDo(this);
-            }
-        }
         for (Instruction n = block; n != null; n = last.next()) {
             n.allValuesDo(this);
             if (n.subst != null && last != null) {
--- a/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/target/amd64/AMD64LIRGenerator.java	Wed May 18 18:09:20 2011 +0200
@@ -33,6 +33,9 @@
 import com.sun.c1x.util.*;
 import com.sun.cri.bytecode.*;
 import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
+import com.sun.cri.ri.RiType.*;
+import com.sun.cri.xir.*;
 
 /**
  * This class implements the X86-specific portion of the LIR generator.
@@ -518,4 +521,23 @@
         assert x.defaultSuccessor() == x.falseSuccessor() : "wrong destination above";
         lir.jump(x.defaultSuccessor());
     }
+
+    @Override
+    public void visitExceptionDispatch(ExceptionDispatch x) {
+        // TODO ls: this needs some more work...
+
+        RiType riType = x.handler().handler.catchType();
+        assert riType.isResolved();
+
+        XirArgument obj = toXirArgument(x.exception());
+        XirArgument clazz = toXirArgument(riType.getEncoding(Representation.ObjectHub));
+        XirSnippet snippet = xir.genInstanceOf(site(x), obj, clazz, riType);
+        CiValue result = emitXir(snippet, x, stateFor(x), null, true);
+
+        lir.cmp(Condition.EQ, result, CiConstant.TRUE);
+        lir.branch(Condition.EQ, CiKind.Boolean, x.catchSuccessor());
+
+        lir.jump(x.otherSuccessor());
+    }
+
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java	Wed May 18 18:09:20 2011 +0200
@@ -105,7 +105,8 @@
     /**
      * Gets a copy of this frame state without the stack.
      */
-    public FrameState duplicateWithEmptyStack() {
+    @Override
+    public FrameState duplicateWithEmptyStack(int bci) {
         FrameState other = new FrameState(bci, localsSize, 0, locksSize(), graph());
         for (int i = 0; i < localsSize; i++) {
             other.inputs().set(i, localAt(i));
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateAccess.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateAccess.java	Wed May 18 18:09:20 2011 +0200
@@ -42,4 +42,6 @@
 
     Value stackAt(int i);
 
+    FrameState duplicateWithEmptyStack(int bci);
+
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java	Wed May 18 18:09:20 2011 +0200
@@ -95,6 +95,11 @@
         return new FrameState(bci, locals, stack, stackIndex, locks, graph);
     }
 
+    @Override
+    public FrameState duplicateWithEmptyStack(int bci) {
+        return new FrameState(bci, locals, new Value[0], 0, locks, graph);
+    }
+
     /**
      * Pushes an instruction onto the stack with the expected type.
      * @param kind the type expected for this instruction
--- a/graal/GraalGraphviz/src/com/oracle/graal/graph/vis/GraphvizPrinter.java	Fri May 13 17:09:20 2011 -0700
+++ b/graal/GraalGraphviz/src/com/oracle/graal/graph/vis/GraphvizPrinter.java	Wed May 18 18:09:20 2011 +0200
@@ -25,7 +25,6 @@
 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;
@@ -130,49 +129,54 @@
     }
 
     private void printNode(String name, String label, int ninputs, int nsuccessors) {
+        int minWidth = Math.min(label.length() / 3, 10);
+        minWidth = Math.max(minWidth, Math.max(ninputs + 1, nsuccessors + 1));
         out.println(name + "  [shape=plaintext,");
-        out.println("   label=< <TABLE BORDER=\"0\" CELLSPACING=\"0\"><TR><TD CELLPADDING=\"0\">");
-        out.println("    <TABLE BORDER=\"0\" CELLSPACING=\"2\" CELLPADDING=\"0\"><TR>");
-        out.println("    <TD WIDTH=\"15\" HEIGHT=\"5\" PORT=\"predecessors\" BGCOLOR=\"rosybrown1\"></TD></TR></TABLE>");
-        out.println("    </TD><TD COLSPAN=\"2\" CELLPADDING=\"0\" ALIGN=\"RIGHT\"><TABLE BORDER=\"0\" CELLSPACING=\"2\" CELLPADDING=\"0\"><TR>");
+        out.println("   label=< <TABLE BORDER=\"0\" CELLSPACING=\"0\"><TR>");
 
-        if ((ninputs == 1 && nsuccessors == 1) || (ninputs == 0 && nsuccessors == 0)) {
-            out.println("    <TD WIDTH=\"15\" HEIGHT=\"5\"></TD>");
-        }
+        printPort("predecessors", "rosybrown1");
 
-        for (int i = 0; i < nsuccessors - ninputs; i++) {
-            out.println("    <TD WIDTH=\"15\" HEIGHT=\"5\"></TD>");
+        for (int i = 1; i < minWidth - ninputs; i++) {
+            printEmptyPort();
         }
 
         for (int i = 0; i < ninputs; i++) {
-            out.println("    <TD WIDTH=\"15\" HEIGHT=\"5\" PORT=\"in" + i + "\" BGCOLOR=\"lightgrey\"></TD>");
+            printPort("in" + i, "lightgrey");
         }
 
         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>");
+        out.println("    </TR><TR><TD BORDER=\"1\" COLSPAN=\"" + minWidth + "\" BGCOLOR=\"" + NODE_BGCOLOR_STRING + "\">" + label + "</TD></TR><TR>");
 
         for (int i = 0; i < nsuccessors; i++) {
-            out.println("    <TD WIDTH=\"15\" HEIGHT=\"5\" PORT=\"succ" + i + "\" BGCOLOR=\"rosybrown1\"></TD>");
+            printPort("succ" + i, "rosybrown1");
         }
 
-        for (int i = 0; i < ninputs - nsuccessors; i++) {
-            out.println("    <TD WIDTH=\"15\" HEIGHT=\"5\"></TD>");
+        for (int i = 1; i < minWidth - nsuccessors; i++) {
+            printEmptyPort();
         }
 
-        if ((ninputs == 1 && nsuccessors == 1) || (ninputs == 0 && nsuccessors == 0)) {
-            out.println("    <TD WIDTH=\"15\" HEIGHT=\"5\"></TD>");
-        }
+        printPort("usages", "lightgrey");
 
-        out.println("    </TR></TABLE></TD><TD CELLPADDING=\"0\"><TABLE BORDER=\"0\" CELLSPACING=\"2\" CELLPADDING=\"0\"><TR>");
-        out.println("    <TD WIDTH=\"15\" HEIGHT=\"5\" PORT=\"usages\" BGCOLOR=\"lightgrey\"></TD></TR></TABLE></TD></TR></TABLE>>]; ");
+        out.println("    </TR></TABLE>>]; ");
+    }
+
+    private void printPort(String name, String color) {
+        out.print("    <TD CELLPADDING=\"0\" WIDTH=\"15\"><TABLE BORDER=\"0\" CELLSPACING=\"2\" CELLPADDING=\"0\"><TR><TD WIDTH=\"15\" HEIGHT=\"5\" PORT=\"");
+        out.print(name);
+        out.print("\" BGCOLOR=\"");
+        out.print(color);
+        out.println("\"></TD></TR></TABLE></TD>");
+    }
+
+    private void printEmptyPort() {
+        out.print("    <TD CELLPADDING=\"0\" WIDTH=\"15\"><TABLE BORDER=\"0\" CELLSPACING=\"2\" CELLPADDING=\"0\"><TR><TD WIDTH=\"15\" HEIGHT=\"5\"></TD></TR></TABLE></TD>");
     }
 
     private void printControlEdge(int from, int fromPort, int to) {
-        out.println("n" + from + ":succ" + fromPort + " -> n" + to + ":predecessors:n [color=red, weight=10];");
+        out.println("n" + from + ":succ" + fromPort + " -> n" + to + ":predecessors:n [color=red, weight=2];");
     }
 
     private void printDataEdge(int from, int fromPort, int to) {
--- a/graal/hotspot/hotspot Default.launch	Fri May 13 17:09:20 2011 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-<?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/CRI/bin:${workspace_loc:hotspot}/../../../maxine/Base/bin:${workspace_loc:hotspot}/../../../maxine/Assembler/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>