changeset 5742:a8c6104ef526

Merge
author Gilles Duboscq <duboscq@ssw.jku.at>
date Mon, 02 Jul 2012 18:20:25 +0200
parents c84c75339af1 (current diff) dba56a3344ba (diff)
children e17ab95e06aa d5ce56698bb3
files graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRDebugInfo.java
diffstat 85 files changed, 4706 insertions(+), 1327 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/simple/AssignRegisters.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/simple/AssignRegisters.java	Mon Jul 02 18:20:25 2012 +0200
@@ -49,6 +49,7 @@
         ValueProcedure useProc =          new ValueProcedure() { @Override public Value doValue(Value value) { return use(value); } };
         ValueProcedure defProc =          new ValueProcedure() { @Override public Value doValue(Value value) { return def(value); } };
         ValueProcedure setReferenceProc = new ValueProcedure() { @Override public Value doValue(Value value) { return setReference(value); } };
+        StateProcedure finishProc =       new StateProcedure() { @Override public void doState(LIRFrameState state) { state.finish((BitSet) (curRegisterRefMap.clone()), (BitSet) (curFrameRefMap.clone()), frameMap); } };
 
         Debug.log("==== start assign registers ====");
         for (int i = lir.linearScanOrder().size() - 1; i >= 0; i--) {
@@ -70,17 +71,8 @@
                 op.forEachState(useProc);
                 op.forEachAlive(useProc);
 
-                if (op.info != null) {
-                    Debug.log("    registerRefMap: %s  frameRefMap: %s", curRegisterRefMap, curFrameRefMap);
-                    op.info.finish((BitSet) (curRegisterRefMap.clone()), (BitSet) (curFrameRefMap.clone()), frameMap);
-
-                    if (op instanceof LIRXirInstruction) {
-                        LIRXirInstruction xir = (LIRXirInstruction) op;
-                        if (xir.infoAfter != null) {
-                            xir.infoAfter.finish((BitSet) (curRegisterRefMap.clone()), (BitSet) (curFrameRefMap.clone()), frameMap);
-                        }
-                    }
-                }
+                // Build the reference map for the GC.
+                op.forEachState(finishProc);
 
                 // Process input operands after assigning the reference map, so that input operands that are used
                 // for the last time at this instruction are not part of the reference map.
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/simple/LinearScanAllocator.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/simple/LinearScanAllocator.java	Mon Jul 02 18:20:25 2012 +0200
@@ -341,20 +341,20 @@
     }
 
     private Value use(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        assert mode == OperandMode.Input || mode == OperandMode.Alive;
+        assert mode == OperandMode.USE || mode == OperandMode.ALIVE;
         if (isVariable(value)) {
             // State values are not recorded beforehand because it does not matter if they are spilled. Still, it is necessary to record them as used now.
             recordUse(value);
 
             Location curLoc = curLocations.get(asVariable(value));
-            if (isStackSlot(curLoc.location) && flags.contains(OperandFlag.Stack)) {
+            if (isStackSlot(curLoc.location) && flags.contains(OperandFlag.STACK)) {
                 Debug.log("    use %s %s: use current stack slot %s", mode, value, curLoc.location);
                 return curLoc;
             }
             if (isRegister(curLoc.location)) {
                 int regNum = asRegister(curLoc.location).number;
                 assert curInRegisterState[regNum] == curLoc;
-                if (mode == OperandMode.Input || curOutRegisterState[regNum] == curLoc) {
+                if (mode == OperandMode.USE || curOutRegisterState[regNum] == curLoc) {
                     Debug.log("    use %s %s: use current register %s", mode, value, curLoc.location);
                     return curLoc;
                 }
@@ -373,10 +373,10 @@
         return value;
     }
 
-    private static final EnumSet<OperandFlag> SPILL_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
+    private static final EnumSet<OperandFlag> SPILL_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
 
     private Value def(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        assert mode == OperandMode.Temp || mode == OperandMode.Output;
+        assert mode == OperandMode.TEMP || mode == OperandMode.DEF;
         if (isVariable(value)) {
             Debug.log("    def %s %s", mode, value);
             assert curLocations.get(asVariable(value)) == null;
@@ -396,7 +396,7 @@
             if (in != null && in != out && isLocation(in) && curLocations.get(asLocation(in).variable) == in) {
                 Debug.log("    %s was evicted by %s, need to allocate new location", in, out);
                 Location oldLoc = asLocation(in);
-                Location newLoc = allocateRegister(oldLoc.variable, OperandMode.Alive, SPILL_FLAGS);
+                Location newLoc = allocateRegister(oldLoc.variable, OperandMode.ALIVE, SPILL_FLAGS);
                 assert oldLoc != newLoc;
                 moveResolver.add(oldLoc, newLoc);
             }
@@ -417,7 +417,7 @@
                 Value phiInput = phiInputs[i];
 
                 if (isVariable(phiDefinition)) {
-                    Location hintResult = processRegisterHint(asVariable(phiDefinition), OperandMode.Output, phiInput);
+                    Location hintResult = processRegisterHint(asVariable(phiDefinition), OperandMode.DEF, phiInput);
                     if (hintResult != null) {
                         phiDefinitions[i] = hintResult;
                     }
@@ -444,7 +444,7 @@
     }
 
     private Location allocateRegister(final Variable variable, final OperandMode mode, EnumSet<OperandFlag> flags) {
-        if (flags.contains(OperandFlag.RegisterHint)) {
+        if (flags.contains(OperandFlag.HINT)) {
             Value hintResult = curOp.forEachRegisterHint(variable, mode, new ValueProcedure() {
                 @Override
                 public Value doValue(Value registerHint) {
@@ -476,7 +476,7 @@
             }
         }
 
-        if (flags.contains(OperandFlag.Stack) && betterSpillCandidate(curLocations.get(variable), bestSpillCandidate)) {
+        if (flags.contains(OperandFlag.STACK) && betterSpillCandidate(curLocations.get(variable), bestSpillCandidate)) {
             return selectSpillSlot(variable);
         }
 
@@ -509,11 +509,11 @@
 
     private boolean isFree(Register reg, OperandMode mode) {
         switch (mode) {
-            case Input:  return curInRegisterState[reg.number] == null;
-            case Alive:  return curInRegisterState[reg.number] == null && curOutRegisterState[reg.number] == null;
-            case Temp:   return curOutRegisterState[reg.number] == null;
-            case Output: return curOutRegisterState[reg.number] == null;
-            default:     throw GraalInternalError.shouldNotReachHere();
+            case USE: return curInRegisterState[reg.number] == null;
+            case ALIVE: return curInRegisterState[reg.number] == null && curOutRegisterState[reg.number] == null;
+            case TEMP: return curOutRegisterState[reg.number] == null;
+            case DEF: return curOutRegisterState[reg.number] == null;
+            default: throw GraalInternalError.shouldNotReachHere();
         }
     }
 
@@ -552,7 +552,7 @@
         assert isFree(reg, mode);
 
         Location loc = new Location(variable, reg.asValue(variable.kind));
-        if (mode == OperandMode.Input || mode == OperandMode.Alive) {
+        if (mode == OperandMode.USE || mode == OperandMode.ALIVE) {
             curInRegisterState[reg.number] = loc;
         }
         curOutRegisterState[reg.number] = loc;
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/simple/SpillAllAllocator.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/simple/SpillAllAllocator.java	Mon Jul 02 18:20:25 2012 +0200
@@ -290,8 +290,8 @@
     }
 
     private Value load(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        assert mode == OperandMode.Input || mode == OperandMode.Alive;
-        if (flags.contains(OperandFlag.Stack)) {
+        assert mode == OperandMode.USE || mode == OperandMode.ALIVE;
+        if (flags.contains(OperandFlag.STACK)) {
             return useSlot(value);
         }
         if (isVariable(value)) {
@@ -301,7 +301,7 @@
                 // This variable has already been processed before.
                 Debug.log("      found location %s", regLoc);
             } else {
-                regLoc = allocateRegister(asVariable(value), curInRegisterState, mode == OperandMode.Alive ? curOutRegisterState : null, mode, flags);
+                regLoc = allocateRegister(asVariable(value), curInRegisterState, mode == OperandMode.ALIVE ? curOutRegisterState : null, mode, flags);
                 Location stackLoc = curStackLocations.get(asVariable(value));
                 assert stackLoc != null;
                 moveResolver.add(stackLoc, regLoc);
@@ -314,15 +314,15 @@
     }
 
     private Value spill(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        assert mode == OperandMode.Temp || mode == OperandMode.Output;
-        if (flags.contains(OperandFlag.Stack)) {
+        assert mode == OperandMode.TEMP || mode == OperandMode.DEF;
+        if (flags.contains(OperandFlag.STACK)) {
             return defSlot(value);
         }
         if (isVariable(value)) {
             Debug.log("    spill %s", value);
             assert curStackLocations.get(asVariable(value)) == null;
             Location regLoc = allocateRegister(asVariable(value), null, curOutRegisterState, mode, flags);
-            if (mode == OperandMode.Output) {
+            if (mode == OperandMode.DEF) {
                 Location stackLoc = new Location(asVariable(value), frameMap.allocateSpillSlot(value.kind));
                 curStackLocations.put(stackLoc);
                 moveResolver.add(regLoc, stackLoc);
@@ -360,7 +360,7 @@
     }
 
     private Location allocateRegister(final Variable variable, final Object[] inRegisterState, final Object[] outRegisterState, OperandMode mode, EnumSet<OperandFlag> flags) {
-        if (flags.contains(OperandFlag.RegisterHint)) {
+        if (flags.contains(OperandFlag.HINT)) {
             Value result = curInstruction.forEachRegisterHint(variable, mode, new ValueProcedure() {
                 @Override
                 public Value doValue(Value registerHint) {
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/util/IntervalPrinter.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/util/IntervalPrinter.java	Mon Jul 02 18:20:25 2012 +0200
@@ -167,7 +167,7 @@
                 if (op.hasCall()) {
                     intervals.get("call").ranges.add(new Range(curOpId, curOpId + 1));
                 }
-                if (op.info != null) {
+                if (op.hasState()) {
                     intervals.get("st").ranges.add(new Range(curOpId, curOpId + 1));
                 }
             }
@@ -228,7 +228,7 @@
     private String useKind(EnumSet<OperandFlag> flags) {
         if (curUseKind != null) {
             return curUseKind;
-        } else if (flags.contains(OperandFlag.Stack)) {
+        } else if (flags.contains(OperandFlag.STACK)) {
             return "S";
         } else {
             return "M";
@@ -242,7 +242,7 @@
                 interval.uses.add(new UsePosition(curOpId, useKind(flags)));
             }
             if (interval.lastTo == 0) {
-                interval.lastTo = curOpId + (mode == OperandMode.Alive ? 1 : 0);
+                interval.lastTo = curOpId + (mode == OperandMode.ALIVE ? 1 : 0);
             }
         }
         return value;
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/util/RegisterVerifier.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/util/RegisterVerifier.java	Mon Jul 02 18:20:25 2012 +0200
@@ -189,7 +189,7 @@
     private Value use(Value value, EnumSet<OperandFlag> flags) {
         if (!isConstant(value) && value != Value.IllegalValue && !isIgnoredRegister(value)) {
             Value actual = curInputState.get(key(value));
-            if (actual == null && flags.contains(OperandFlag.Uninitialized)) {
+            if (actual == null && flags.contains(OperandFlag.UNINITIALIZED)) {
                 // OK, since uninitialized values are allowed explicitly.
             } else if (value != actual) {
                 Debug.log("Error in register allocation: %s != %s for key %s", value, actual, key(value));
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/ControlFlowOptimizer.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/ControlFlowOptimizer.java	Mon Jul 02 18:20:25 2012 +0200
@@ -106,7 +106,7 @@
 
         // block must have exactly one successor
 
-        return instructions.size() == 2 && instructions.get(instructions.size() - 1).info == null;
+        return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState();
     }
 
     private void deleteEmptyBlocks(List<Block> code) {
@@ -159,7 +159,7 @@
             if (lastOp instanceof StandardOp.JumpOp) {
                 StandardOp.JumpOp lastJump = (StandardOp.JumpOp) lastOp;
 
-                if (lastOp.info == null) {
+                if (!lastOp.hasState()) {
                     if (lastJump.destination().label() == ((StandardOp.LabelOp) code.get(i + 1).lir.get(0)).getLabel()) {
                         // delete last branch instruction
                         Util.truncate(instructions, instructions.size() - 1);
@@ -169,7 +169,7 @@
                         if (prevOp instanceof StandardOp.BranchOp) {
                             StandardOp.BranchOp prevBranch = (StandardOp.BranchOp) prevOp;
 
-                            if (prevBranch.destination().label() == ((StandardOp.LabelOp) code.get(i + 1).lir.get(0)).getLabel() && prevOp.info == null) {
+                            if (prevBranch.destination().label() == ((StandardOp.LabelOp) code.get(i + 1).lir.get(0)).getLabel() && !prevOp.hasState()) {
                                 // eliminate a conditional branch to the immediate successor
                                 prevBranch.negate(lastJump.destination());
                                 Util.truncate(instructions, instructions.size() - 1);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/EdgeMoveOptimizer.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/EdgeMoveOptimizer.java	Mon Jul 02 18:20:25 2012 +0200
@@ -79,8 +79,7 @@
 
     /**
      * Determines if two operations are both {@linkplain MoveOp moves}
-     * that have the same {@linkplain MoveOp#getInput() source} and {@linkplain MoveOp#getResult() destination}
-     * operands and they have the same {@linkplain LIRInstruction#info debug info}.
+     * that have the same {@linkplain MoveOp#getInput() source} and {@linkplain MoveOp#getResult() destination} operands.
      *
      * @param op1 the first instruction to compare
      * @param op2 the second instruction to compare
@@ -138,7 +137,7 @@
             assert pred.suxAt(0) == block : "invalid control flow";
             assert predInstructions.get(predInstructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump";
 
-            if (predInstructions.get(predInstructions.size() - 1).info != null) {
+            if (predInstructions.get(predInstructions.size() - 1).hasState()) {
                 // can not optimize instructions that have debug info
                 return;
             }
@@ -195,13 +194,13 @@
 
         assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump";
 
-        if (instructions.get(instructions.size() - 1).info != null) {
+        if (instructions.get(instructions.size() - 1).hasState()) {
             // cannot optimize instructions when debug info is needed
             return;
         }
 
         LIRInstruction branch = instructions.get(instructions.size() - 2);
-        if (!(branch instanceof StandardOp.BranchOp) || branch.info != null) {
+        if (!(branch instanceof StandardOp.BranchOp) || branch.hasState()) {
             // not a valid case for optimization
             // currently, only blocks that end with two branches (conditional branch followed
             // by unconditional branch) are optimized
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Mon Jul 02 18:20:25 2012 +0200
@@ -759,7 +759,7 @@
             int len = splitChildren.size();
 
             // in outputMode, the end of the interval (opId == cur.to()) is not valid
-            int toOffset = (mode == LIRInstruction.OperandMode.Output ? 0 : 1);
+            int toOffset = (mode == LIRInstruction.OperandMode.DEF ? 0 : 1);
 
             int i;
             for (i = 0; i < len; i++) {
@@ -905,7 +905,7 @@
     }
 
     void addUsePos(int pos, RegisterPriority registerPriority) {
-        assert covers(pos, LIRInstruction.OperandMode.Input) : "use position not covered by live range";
+        assert covers(pos, LIRInstruction.OperandMode.USE) : "use position not covered by live range";
 
         // do not add use positions for precolored intervals because they are never used
         if (registerPriority != RegisterPriority.None && isVariable(operand)) {
@@ -1063,7 +1063,7 @@
         if (cur != Range.EndMarker) {
             assert cur.to != cur.next.from : "ranges not separated";
 
-            if (mode == LIRInstruction.OperandMode.Output) {
+            if (mode == LIRInstruction.OperandMode.DEF) {
                 return cur.from <= opId && opId < cur.to;
             } else {
                 return cur.from <= opId && opId <= cur.to;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Mon Jul 02 18:20:25 2012 +0200
@@ -22,11 +22,12 @@
  */
 package com.oracle.graal.compiler.alloc;
 
-import static com.oracle.graal.alloc.util.LocationUtil.*;
 import static com.oracle.graal.api.code.CodeUtil.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+
 import java.util.*;
 
-import com.oracle.max.criutils.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
@@ -38,9 +39,13 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.*;
-import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.StateProcedure;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.cfg.*;
+import com.oracle.max.criutils.*;
 
 /**
  * An implementation of the linear scan register allocator algorithm described
@@ -867,16 +872,13 @@
                         TTY.println("  used in block B%d", block.getId());
                         for (LIRInstruction ins : block.lir) {
                             TTY.println(ins.id() + ": " + ins.toString());
-                            LIRDebugInfo info = ins.info;
-                            if (info != null) {
-                                info.forEachState(new ValueProcedure() {
-                                    @Override
-                                    public Value doValue(Value liveStateOperand) {
-                                        TTY.println("   operand=" + liveStateOperand);
-                                        return liveStateOperand;
-                                    }
-                                });
-                            }
+                            ins.forEachState(new ValueProcedure() {
+                                @Override
+                                public Value doValue(Value liveStateOperand) {
+                                    TTY.println("   operand=" + liveStateOperand);
+                                    return liveStateOperand;
+                                }
+                            });
                         }
                     }
                     if (blockData.get(block).liveKill.get(operandNum)) {
@@ -1032,7 +1034,7 @@
      * Determines the priority which with an instruction's input operand will be allocated a register.
      */
     static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
-        if (flags.contains(OperandFlag.Stack)) {
+        if (flags.contains(OperandFlag.STACK)) {
             return RegisterPriority.ShouldHaveRegister;
         }
         // all other operands require a register
@@ -1068,7 +1070,7 @@
     }
 
     void addRegisterHint(final LIRInstruction op, final Value targetValue, OperandMode mode, EnumSet<OperandFlag> flags) {
-        if (flags.contains(OperandFlag.RegisterHint) && isVariableOrRegister(targetValue)) {
+        if (flags.contains(OperandFlag.HINT) && isVariableOrRegister(targetValue)) {
 
             op.forEachRegisterHint(targetValue, mode, new ValueProcedure() {
                 @Override
@@ -1401,21 +1403,21 @@
         assert isVariable(operand) : "register number out of bounds";
         assert intervalFor(operand) != null : "no interval found";
 
-        return splitChildAtOpId(intervalFor(operand), block.getFirstLirInstructionId(), LIRInstruction.OperandMode.Output);
+        return splitChildAtOpId(intervalFor(operand), block.getFirstLirInstructionId(), LIRInstruction.OperandMode.DEF);
     }
 
     Interval intervalAtBlockEnd(Block block, Value operand) {
         assert isVariable(operand) : "register number out of bounds";
         assert intervalFor(operand) != null : "no interval found";
 
-        return splitChildAtOpId(intervalFor(operand), block.getLastLirInstructionId() + 1, LIRInstruction.OperandMode.Output);
+        return splitChildAtOpId(intervalFor(operand), block.getLastLirInstructionId() + 1, LIRInstruction.OperandMode.DEF);
     }
 
     Interval intervalAtOpId(Value operand, int opId) {
         assert isVariable(operand) : "register number out of bounds";
         assert intervalFor(operand) != null : "no interval found";
 
-        return splitChildAtOpId(intervalFor(operand), opId, LIRInstruction.OperandMode.Input);
+        return splitChildAtOpId(intervalFor(operand), opId, LIRInstruction.OperandMode.USE);
     }
 
     void resolveCollectMappings(Block fromBlock, Block toBlock, MoveResolver moveResolver) {
@@ -1697,20 +1699,7 @@
     }
 
 
-    private void computeDebugInfo(IntervalWalker iw, LIRInstruction op) {
-        assert iw != null : "interval walker needed for debug information";
-        computeDebugInfo(iw, op, op.info);
-
-        if (op instanceof LIRXirInstruction) {
-            LIRXirInstruction xir = (LIRXirInstruction) op;
-            if (xir.infoAfter != null) {
-                computeDebugInfo(iw, op, xir.infoAfter);
-            }
-        }
-    }
-
-
-    private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRDebugInfo info) {
+    private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) {
         BitSet registerRefMap = op.hasCall() ? null : frameMap.initRegisterRefMap();
         BitSet frameRefMap = frameMap.initFrameRefMap();
         computeOopMap(iw, op, registerRefMap, frameRefMap);
@@ -1719,7 +1708,7 @@
             @Override
             public Value doValue(Value operand) {
                 int tempOpId = op.id();
-                OperandMode mode = OperandMode.Input;
+                OperandMode mode = OperandMode.USE;
                 Block block = blockForId(tempOpId);
                 if (block.numberOfSux() == 1 && tempOpId == block.getLastLirInstructionId()) {
                     // generating debug information for the last instruction of a block.
@@ -1731,7 +1720,7 @@
                     if (instr instanceof StandardOp.JumpOp) {
                         if (blockData.get(block).liveOut.get(operandNumber(operand))) {
                             tempOpId = block.suxAt(0).getFirstLirInstructionId();
-                            mode = OperandMode.Output;
+                            mode = OperandMode.DEF;
                         }
                     }
                 }
@@ -1748,7 +1737,7 @@
         info.finish(registerRefMap, frameRefMap, frameMap);
     }
 
-    private void assignLocations(List<LIRInstruction> instructions, IntervalWalker iw) {
+    private void assignLocations(List<LIRInstruction> instructions, final IntervalWalker iw) {
         int numInst = instructions.size();
         boolean hasDead = false;
 
@@ -1774,10 +1763,13 @@
             op.forEachTemp(assignProc);
             op.forEachOutput(assignProc);
 
-            if (op.info != null) {
-                // compute reference map and debug information
-                computeDebugInfo(iw, op);
-            }
+            // compute reference map and debug information
+            op.forEachState(new StateProcedure() {
+                @Override
+                protected void doState(LIRFrameState state) {
+                    computeDebugInfo(iw, op, state);
+                }
+            });
 
             // remove useless moves
             if (op instanceof MoveOp) {
@@ -2049,7 +2041,7 @@
             for (int j = 0; j < instructions.size(); j++) {
                 LIRInstruction op = instructions.get(j);
 
-                if (op.info != null) {
+                if (op.hasState()) {
                     iw.walkBefore(op.id());
                     boolean checkLive = true;
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Mon Jul 02 18:20:25 2012 +0200
@@ -867,8 +867,8 @@
             return;
         }
 
-        Interval beginHint = registerHint.getSplitChildAtOpId(beginPos, LIRInstruction.OperandMode.Input, allocator);
-        Interval endHint = registerHint.getSplitChildAtOpId(endPos, LIRInstruction.OperandMode.Output, allocator);
+        Interval beginHint = registerHint.getSplitChildAtOpId(beginPos, LIRInstruction.OperandMode.USE, allocator);
+        Interval endHint = registerHint.getSplitChildAtOpId(endPos, LIRInstruction.OperandMode.DEF, allocator);
         if (beginHint == endHint || beginHint.to() != beginPos || endHint.from() != endPos) {
             // registerHint must be split : otherwise the re-writing of use positions does not work
             return;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Mon Jul 02 18:20:25 2012 +0200
@@ -44,7 +44,7 @@
 
     private HashMap<VirtualObjectNode, VirtualObject> virtualObjects = new HashMap<>();
 
-    public LIRDebugInfo build(FrameState topState, LockScope locks, List<StackSlot> pointerSlots, LabelRef exceptionEdge, long leafGraphId) {
+    public LIRFrameState build(FrameState topState, LockScope locks, List<StackSlot> pointerSlots, LabelRef exceptionEdge, long leafGraphId) {
         assert virtualObjects.size() == 0;
         BytecodeFrame frame = computeFrameForState(topState, locks, leafGraphId);
 
@@ -94,7 +94,7 @@
             virtualObjects.clear();
         }
 
-        return new LIRDebugInfo(frame, virtualObjectsArray, pointerSlots, exceptionEdge);
+        return new LIRFrameState(frame, virtualObjectsArray, pointerSlots, exceptionEdge);
     }
 
     private BytecodeFrame computeFrameForState(FrameState state, LockScope locks, long leafGraphId) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon Jul 02 18:20:25 2012 +0200
@@ -261,21 +261,21 @@
         return LabelRef.forSuccessor(currentBlock, suxIndex);
     }
 
-    public LIRDebugInfo state() {
+    public LIRFrameState state() {
         assert lastState != null : "must have state before instruction";
         return stateFor(lastState, -1);
     }
 
-    public LIRDebugInfo state(long leafGraphId) {
+    public LIRFrameState state(long leafGraphId) {
         assert lastState != null : "must have state before instruction";
         return stateFor(lastState, leafGraphId);
     }
 
-    public LIRDebugInfo stateFor(FrameState state, long leafGraphId) {
+    public LIRFrameState stateFor(FrameState state, long leafGraphId) {
         return stateFor(state, null, null, leafGraphId);
     }
 
-    public LIRDebugInfo stateFor(FrameState state, List<StackSlot> pointerSlots, LabelRef exceptionEdge, long leafGraphId) {
+    public LIRFrameState stateFor(FrameState state, List<StackSlot> pointerSlots, LabelRef exceptionEdge, long leafGraphId) {
         return debugInfoBuilder.build(state, curLocks, pointerSlots, exceptionEdge, leafGraphId);
     }
 
@@ -552,11 +552,11 @@
         XirArgument obj = toXirArgument(x.object());
         XirArgument lockAddress = lockData == null ? null : toXirArgument(emitLea(lockData));
 
-        LIRDebugInfo stateBefore = state();
+        LIRFrameState stateBefore = state();
         // The state before the monitor enter is used for null checks, so it must not contain the newly locked object.
         curLocks = new LockScope(curLocks, x.stateAfter().inliningIdentifier(), x, lockData);
         // The state after the monitor enter is used for deoptimization, after the monitor has blocked, so it must contain the newly locked object.
-        LIRDebugInfo stateAfter = stateFor(x.stateAfter(), -1);
+        LIRFrameState stateAfter = stateFor(x.stateAfter(), -1);
 
         XirSnippet snippet = xir.genMonitorEnter(site(x, x.object()), obj, lockAddress);
         emitXir(snippet, x, stateBefore, stateAfter, true, null, null);
@@ -576,7 +576,7 @@
         XirArgument obj = toXirArgument(x.object());
         XirArgument lockAddress = lockData == null ? null : toXirArgument(emitLea(lockData));
 
-        LIRDebugInfo stateBefore = state();
+        LIRFrameState stateBefore = state();
         curLocks = curLocks.outer;
 
         XirSnippet snippet = xir.genMonitorExit(site(x, x.object()), obj, lockAddress);
@@ -698,7 +698,7 @@
             // False constants are handled within emitBranch.
         } else {
             // Fall back to a normal branch.
-            LIRDebugInfo info = state(leafGraphId);
+            LIRFrameState info = state(leafGraphId);
             LabelRef stubEntry = createDeoptStub(action, deoptReason, info, comp);
             if (negated) {
                 emitBranch(comp, stubEntry, null, info);
@@ -710,7 +710,7 @@
 
     protected abstract void emitNullCheckGuard(ValueNode object, long leafGraphId);
 
-    public void emitBranch(BooleanNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
+    public void emitBranch(BooleanNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRFrameState info) {
         if (node instanceof IsNullNode) {
             emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, info);
         } else if (node instanceof CompareNode) {
@@ -726,7 +726,7 @@
         }
     }
 
-    private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
+    private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRFrameState info) {
         if (falseSuccessor != null) {
             emitBranch(operand(node.object()), Constant.NULL_OBJECT, Condition.NE, false, falseSuccessor, info);
             if (trueSuccessor != null) {
@@ -737,7 +737,7 @@
         }
     }
 
-    public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRDebugInfo info) {
+    public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRFrameState info) {
         if (falseSuccessorBlock != null) {
             emitBranch(operand(compare.x()), operand(compare.y()), compare.condition().negate(), !compare.unorderedIsTrue(), falseSuccessorBlock, info);
             if (trueSuccessorBlock != null) {
@@ -748,20 +748,20 @@
         }
     }
 
-    private void emitInstanceOfBranch(InstanceOfNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
+    private void emitInstanceOfBranch(InstanceOfNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRFrameState info) {
         XirArgument obj = toXirArgument(x.object());
         XirSnippet snippet = xir.genInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), x.targetClass(), x.profile());
         emitXir(snippet, x, info, null, false, trueSuccessor, falseSuccessor);
     }
 
-    public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRDebugInfo info) {
+    public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRFrameState info) {
         LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock;
         if (block != null) {
             emitJump(block, info);
         }
     }
 
-    public void emitTypeBranch(IsTypeNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
+    public void emitTypeBranch(IsTypeNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRFrameState info) {
         XirArgument thisClass = toXirArgument(x.objectClass());
         XirArgument otherClass = toXirArgument(x.type().getEncoding(Representation.ObjectHub));
         XirSnippet snippet = xir.genTypeBranch(site(x), thisClass, otherClass, x.type());
@@ -814,8 +814,8 @@
 
 
     public abstract void emitLabel(Label label, boolean align);
-    public abstract void emitJump(LabelRef label, LIRDebugInfo info);
-    public abstract void emitBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label, LIRDebugInfo info);
+    public abstract void emitJump(LabelRef label, LIRFrameState info);
+    public abstract void emitBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label, LIRFrameState info);
     public abstract Variable emitCMove(Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
 
     protected FrameState stateBeforeCallWithArguments(FrameState stateAfter, MethodCallTargetNode call, int bci) {
@@ -882,7 +882,7 @@
         if (!target().invokeSnippetAfterArguments) {
             // This is the version currently necessary for Maxine: since the invokeinterface-snippet uses a division, it
             // destroys rdx, which is also used to pass a parameter.  Therefore, the snippet must be before the parameters are assigned to their locations.
-            LIRDebugInfo addrInfo = stateFor(stateBeforeCallWithArguments(x.stateAfter(), callTarget, x.bci()), x.leafGraphId());
+            LIRFrameState addrInfo = stateFor(stateBeforeCallWithArguments(x.stateAfter(), callTarget, x.bci()), x.leafGraphId());
             destinationAddress = emitXir(snippet, x.node(), addrInfo, false);
         }
 
@@ -895,11 +895,11 @@
 
         if (target().invokeSnippetAfterArguments) {
             // This is the version currently active for HotSpot.
-            LIRDebugInfo addrInfo = stateFor(stateBeforeCallWithArguments(x.stateAfter(), callTarget, x.bci()), null, null, x.leafGraphId());
+            LIRFrameState addrInfo = stateFor(stateBeforeCallWithArguments(x.stateAfter(), callTarget, x.bci()), null, null, x.leafGraphId());
             destinationAddress = emitXir(snippet, x.node(), addrInfo, false);
         }
 
-        LIRDebugInfo callInfo = stateFor(x.stateDuring(), null, x instanceof InvokeWithExceptionNode ? getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()) : null, x.leafGraphId());
+        LIRFrameState callInfo = stateFor(x.stateDuring(), null, x instanceof InvokeWithExceptionNode ? getLIRBlock(((InvokeWithExceptionNode) x).exceptionEdge()) : null, x.leafGraphId());
         emitCall(targetMethod, resultOperand, argList, destinationAddress, callInfo, snippet.marks);
 
         if (isLegal(resultOperand)) {
@@ -907,7 +907,7 @@
         }
     }
 
-    protected abstract void emitCall(Object targetMethod, Value result, List<Value> arguments, Value targetAddress, LIRDebugInfo info, Map<XirMark, Mark> marks);
+    protected abstract void emitCall(Object targetMethod, Value result, List<Value> arguments, Value targetAddress, LIRFrameState info, Map<XirMark, Mark> marks);
 
 
     private static Value toStackKind(Value value) {
@@ -942,11 +942,11 @@
     }
 
 
-    protected abstract LabelRef createDeoptStub(DeoptimizationAction action, DeoptimizationReason reason, LIRDebugInfo info, Object deoptInfo);
+    protected abstract LabelRef createDeoptStub(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info, Object deoptInfo);
 
     @Override
     public Variable emitCall(@SuppressWarnings("hiding") Object target, Kind result, Kind[] arguments, boolean canTrap, Value... args) {
-        LIRDebugInfo info = canTrap ? state() : null;
+        LIRFrameState info = canTrap ? state() : null;
 
         Value physReg = resultOperandFor(result);
 
@@ -984,7 +984,7 @@
         frameMap.callsMethod(cc, RuntimeCall);
         List<Value> argList = visitInvokeArguments(cc, x.arguments());
 
-        LIRDebugInfo info = null;
+        LIRFrameState info = null;
         FrameState stateAfter = x.stateAfter();
         if (stateAfter != null) {
             // (cwimmer) I made the code that modifies the operand stack conditional. My scenario: runtime calls to, e.g.,
@@ -1192,11 +1192,11 @@
         return variable;
     }
 
-    protected Value emitXir(XirSnippet snippet, ValueNode x, LIRDebugInfo info, boolean setInstructionResult) {
+    protected Value emitXir(XirSnippet snippet, ValueNode x, LIRFrameState info, boolean setInstructionResult) {
         return emitXir(snippet, x, info, null, setInstructionResult, null, null);
     }
 
-    protected Value emitXir(XirSnippet snippet, ValueNode instruction, LIRDebugInfo info, LIRDebugInfo infoAfter, boolean setInstructionResult, LabelRef trueSuccessor, LabelRef falseSuccessor) {
+    protected Value emitXir(XirSnippet snippet, ValueNode instruction, LIRFrameState info, LIRFrameState infoAfter, boolean setInstructionResult, LabelRef trueSuccessor, LabelRef falseSuccessor) {
         if (GraalOptions.PrintXirTemplates) {
             TTY.println("Emit XIR template " + snippet.template.name);
         }
@@ -1304,9 +1304,9 @@
     }
 
     protected abstract void emitXir(XirSnippet snippet, Value[] operands, Value outputOperand, Value[] inputs, Value[] temps, int[] inputOperandIndices, int[] tempOperandIndices, int outputOperandIndex,
-                    LIRDebugInfo info, LIRDebugInfo infoAfter, LabelRef trueSuccessor, LabelRef falseSuccessor);
+                    LIRFrameState info, LIRFrameState infoAfter, LabelRef trueSuccessor, LabelRef falseSuccessor);
 
-    protected final Value callRuntime(RuntimeCall runtimeCall, LIRDebugInfo info, Value... args) {
+    protected final Value callRuntime(RuntimeCall runtimeCall, LIRFrameState info, Value... args) {
         // get a result register
         Kind result = runtimeCall.resultKind;
         Kind[] arguments = runtimeCall.arguments;
@@ -1336,7 +1336,7 @@
         return physReg;
     }
 
-    protected final Variable callRuntimeWithResult(RuntimeCall runtimeCall, LIRDebugInfo info, Value... args) {
+    protected final Variable callRuntimeWithResult(RuntimeCall runtimeCall, LIRFrameState info, Value... args) {
         Value location = callRuntime(runtimeCall, info, args);
         return emitMove(location);
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java	Mon Jul 02 18:20:25 2012 +0200
@@ -35,12 +35,12 @@
 
 public class AMD64DeoptimizationStub extends AMD64Code {
     public final Label label = new Label();
-    public final LIRDebugInfo info;
+    public final LIRFrameState info;
     public final DeoptimizationAction action;
     public final DeoptimizationReason reason;
     public final Object deoptInfo;
 
-    public AMD64DeoptimizationStub(DeoptimizationAction action, DeoptimizationReason reason, LIRDebugInfo info, Object deoptInfo) {
+    public AMD64DeoptimizationStub(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info, Object deoptInfo) {
         this.action = action;
         this.reason = reason;
         this.info = info;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Mon Jul 02 18:20:25 2012 +0200
@@ -213,12 +213,12 @@
     }
 
     @Override
-    public void emitJump(LabelRef label, LIRDebugInfo info) {
+    public void emitJump(LabelRef label, LIRFrameState info) {
         append(new JumpOp(label, info));
     }
 
     @Override
-    public void emitBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label, LIRDebugInfo info) {
+    public void emitBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label, LIRFrameState info) {
         boolean mirrored = emitCompare(left, right);
         Condition finalCondition = mirrored ? cond.mirror() : cond;
         switch (left.kind.stackKind()) {
@@ -520,7 +520,7 @@
 
     @Override
     public void emitDeoptimizeOnOverflow(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo) {
-        LIRDebugInfo info = state();
+        LIRFrameState info = state();
         LabelRef stubEntry = createDeoptStub(action, reason, info, deoptInfo);
         append(new BranchOp(ConditionFlag.overflow, stubEntry, info));
     }
@@ -528,7 +528,7 @@
 
     @Override
     public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason, Object deoptInfo, long leafGraphId) {
-        LIRDebugInfo info = state(leafGraphId);
+        LIRFrameState info = state(leafGraphId);
         LabelRef stubEntry = createDeoptStub(action, reason, info, deoptInfo);
         append(new JumpOp(stubEntry, info));
     }
@@ -542,7 +542,7 @@
     }
 
     @Override
-    protected void emitCall(Object targetMethod, Value result, List<Value> arguments, Value targetAddress, LIRDebugInfo info, Map<XirMark, Mark> marks) {
+    protected void emitCall(Object targetMethod, Value result, List<Value> arguments, Value targetAddress, LIRFrameState info, Map<XirMark, Mark> marks) {
         if (isConstant(targetAddress)) {
             append(new DirectCallOp(targetMethod, result, arguments.toArray(new Value[arguments.size()]), info, marks));
         } else {
@@ -557,7 +557,7 @@
 
     @Override
     protected void emitXir(XirSnippet snippet, Value[] operands, Value outputOperand, Value[] inputs, Value[] temps, int[] inputOperandIndices, int[] tempOperandIndices, int outputOperandIndex,
-                    LIRDebugInfo info, LIRDebugInfo infoAfter, LabelRef trueSuccessor, LabelRef falseSuccessor) {
+                    LIRFrameState info, LIRFrameState infoAfter, LabelRef trueSuccessor, LabelRef falseSuccessor) {
         append(new AMD64XirOp(snippet, operands, outputOperand, inputs, temps, inputOperandIndices, tempOperandIndices, outputOperandIndex, info, infoAfter, trueSuccessor, falseSuccessor));
     }
 
@@ -565,7 +565,7 @@
     protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
         // Making a copy of the switch value is necessary because jump table destroys the input value
         if (key.kind == Kind.Int) {
-            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key));
+            append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, Value.IllegalValue));
         } else {
             assert key.kind == Kind.Object;
             append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(Kind.Object)));
@@ -585,7 +585,7 @@
     }
 
     @Override
-    protected LabelRef createDeoptStub(DeoptimizationAction action, DeoptimizationReason reason, LIRDebugInfo info, Object deoptInfo) {
+    protected LabelRef createDeoptStub(DeoptimizationAction action, DeoptimizationReason reason, LIRFrameState info, Object deoptInfo) {
         assert info.topFrame.getBCI() >= 0 : "invalid bci for deopt framestate";
         AMD64DeoptimizationStub stub = new AMD64DeoptimizationStub(action, reason, info, deoptInfo);
         lir.stubs.add(stub);
@@ -595,7 +595,7 @@
     @Override
     protected void emitNullCheckGuard(ValueNode object, long leafGraphId) {
         Variable value = load(operand(object));
-        LIRDebugInfo info = state(leafGraphId);
+        LIRFrameState info = state(leafGraphId);
         append(new NullCheckOp(value, info));
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirOp.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirOp.java	Mon Jul 02 18:20:25 2012 +0200
@@ -46,8 +46,8 @@
 
 public class AMD64XirOp extends LIRXirInstruction {
     public AMD64XirOp(XirSnippet snippet, Value[] operands, Value outputOperand, Value[] inputs, Value[] temps, int[] inputOperandIndices, int[] tempOperandIndices, int outputOperandIndex,
-                        LIRDebugInfo info, LIRDebugInfo infoAfter, LabelRef trueSuccessor, LabelRef falseSuccessor) {
-        super("XIR", snippet, operands, outputOperand, inputs, temps, inputOperandIndices, tempOperandIndices, outputOperandIndex, info, infoAfter, trueSuccessor, falseSuccessor);
+                        LIRFrameState info, LIRFrameState infoAfter, LabelRef trueSuccessor, LabelRef falseSuccessor) {
+        super(snippet, operands, outputOperand, inputs, temps, inputOperandIndices, tempOperandIndices, outputOperandIndex, info, infoAfter, trueSuccessor, falseSuccessor);
     }
 
     @Override
@@ -165,7 +165,7 @@
                     Value pointer = operands[inst.x().index];
                     RegisterValue register = assureInRegister(tasm, masm, pointer);
 
-                    AMD64Move.load(tasm, masm, result, new Address(inst.kind, register), (Boolean) inst.extra ? info : null);
+                    AMD64Move.load(tasm, masm, result, new Address(inst.kind, register), (Boolean) inst.extra ? state : null);
                     break;
                 }
 
@@ -174,7 +174,7 @@
                     Value pointer = operands[inst.x().index];
                     assert isRegister(pointer);
 
-                    AMD64Move.store(tasm, masm, new Address(inst.kind, pointer), value, (Boolean) inst.extra ? info : null);
+                    AMD64Move.store(tasm, masm, new Address(inst.kind, pointer), value, (Boolean) inst.extra ? state : null);
                     break;
                 }
 
@@ -201,7 +201,7 @@
                         src = new Address(inst.kind, pointer, index, scale, displacement);
                     }
 
-                    AMD64Move.load(tasm, masm, result, src, canTrap ? info : null);
+                    AMD64Move.load(tasm, masm, result, src, canTrap ? state : null);
                     break;
                 }
 
@@ -245,7 +245,7 @@
                         dst = new Address(inst.kind, pointer, index, scale, displacement);
                     }
 
-                    AMD64Move.store(tasm, masm, dst, value, canTrap ? info : null);
+                    AMD64Move.store(tasm, masm, dst, value, canTrap ? state : null);
                     break;
                 }
 
@@ -271,8 +271,8 @@
                     RegisterValue pointerRegister = assureInRegister(tasm, masm, exchangedAddress);
                     Address addr = new Address(tasm.target.wordKind, pointerRegister);
 
-                    if ((Boolean) inst.extra && info != null) {
-                        tasm.recordImplicitException(masm.codeBuffer.position(), info);
+                    if ((Boolean) inst.extra && state != null) {
+                        tasm.recordImplicitException(masm.codeBuffer.position(), state);
                     }
                     masm.cmpxchgq(asRegister(exchangedVal), addr);
 
@@ -294,7 +294,7 @@
                     }
 
                     RuntimeCallInformation runtimeCallInformation = (RuntimeCallInformation) inst.extra;
-                    AMD64Call.directCall(tasm, masm, runtimeCallInformation.target, (runtimeCallInformation.useInfoAfter) ? infoAfter : info);
+                    AMD64Call.directCall(tasm, masm, runtimeCallInformation.target, (runtimeCallInformation.useInfoAfter) ? stateAfter : state);
 
                     if (inst.result != null && inst.result.kind != Kind.Illegal && inst.result.kind != Kind.Void) {
                         Register returnRegister = tasm.frameMap.registerConfig.getReturnRegister(inst.result.kind);
@@ -386,12 +386,12 @@
                     break;
                 }
                 case Safepoint: {
-                    assert info != null : "Must have debug info in order to create a safepoint.";
-                    tasm.recordSafepoint(masm.codeBuffer.position(), info);
+                    assert state != null : "Must have debug info in order to create a safepoint.";
+                    tasm.recordSafepoint(masm.codeBuffer.position(), state);
                     break;
                 }
                 case NullCheck: {
-                    tasm.recordImplicitException(masm.codeBuffer.position(), info);
+                    tasm.recordImplicitException(masm.codeBuffer.position(), state);
                     Value pointer = operands[inst.x().index];
                     masm.nullCheck(asRegister(pointer));
                     break;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/counters/MethodEntryCounters.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/counters/MethodEntryCounters.java	Mon Jul 02 18:20:25 2012 +0200
@@ -32,9 +32,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.max.asm.*;
@@ -42,7 +41,6 @@
 import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.max.criutils.*;
 
-
 public class MethodEntryCounters {
     protected static final class Counter implements Comparable<Counter> {
         protected static ArrayList<Counter> counters = new ArrayList<>();
@@ -64,23 +62,24 @@
     }
 
 
+    @Opcode("ENTRY_COUNTER")
     protected static class AMD64MethodEntryOp extends AMD64LIRInstruction {
+        @Temp protected Value counterArr;
+        @Temp protected Value callerPc;
+
         protected static int codeSize;
 
         protected final Counter counter;
 
         protected AMD64MethodEntryOp(Counter counter, Value counterArr, Value callerPc) {
-            super("ENTRY_COUNTER", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, new Value[] {counterArr, callerPc});
             this.counter = counter;
+            this.counterArr = counterArr;
+            this.callerPc = callerPc;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
             int start = masm.codeBuffer.position();
-
-            Value counterArr = temp(0);
-            Value callerPc = temp(1);
-
             int off = Unsafe.getUnsafe().arrayBaseOffset(long[].class);
             int scale = Unsafe.getUnsafe().arrayIndexScale(long[].class);
 
@@ -114,16 +113,6 @@
             assert codeSize == 0 || codeSize == size;
             codeSize = size;
         }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Temp && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Temp && index == 1) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
     }
 
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Mon Jul 02 18:20:25 2012 +0200
@@ -62,7 +62,7 @@
     public void generate(LIRGenerator gen) {
         Variable result = gen.newVariable(Kind.Object);
         gen.emitMove(gen.operand(hub), AMD64.rdx.asValue(Kind.Object));
-        LIRDebugInfo info = gen.state();
+        LIRFrameState info = gen.state();
         AMD64NewInstanceStubCallOp op = new AMD64NewInstanceStubCallOp(result, AMD64.rdx.asValue(Kind.Object), info);
         gen.append(op);
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TailcallNode.java	Mon Jul 02 18:20:25 2012 +0200
@@ -72,6 +72,6 @@
 
         Value entry = gen.emitLoad(new Address(Kind.Long, gen.operand(target), config.nmethodEntryOffset), false);
 
-        gen.append(new AMD64TailcallOp(argList, entry, cc.locations));
+        gen.append(new AMD64TailcallOp(argList, entry));
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VerifyOopStubCall.java	Mon Jul 02 18:20:25 2012 +0200
@@ -45,7 +45,7 @@
 
     @Override
     public void generate(LIRGenerator gen) {
-        LIRDebugInfo info = gen.state();
+        LIRFrameState info = gen.state();
         AMD64VerifyOopStubCallOp op = new AMD64VerifyOopStubCallOp(gen.operand(object), info);
         gen.append(op);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/AMD64NewInstanceStubCallOp.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/AMD64NewInstanceStubCallOp.java	Mon Jul 02 18:20:25 2012 +0200
@@ -24,48 +24,45 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 
-import java.util.*;
-
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.max.asm.target.amd64.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
 
 /**
  * LIR instruction for calling HotSpot's {@code new_instance} stub. This stub is declared in c1_Runtime1.hpp
  * and implemented in Runtime1::generate_code_for() which is located in c1_Runtime1_x86.cpp.
  */
+@Opcode("NEW_INSTANCE")
 public class AMD64NewInstanceStubCallOp extends AMD64LIRInstruction {
-    public AMD64NewInstanceStubCallOp(Value result, Value hub, LIRDebugInfo info) {
-        super("NEW_INSTANCE", new Value[] {result}, info, new Value[] {hub}, NO_OPERANDS, new Value[]{AMD64.rax.asValue(Kind.Object)});
+    @Def protected Value result;
+    @Use protected Value hub;
+    @Temp protected Value temp;
+    @State protected LIRFrameState state;
+
+    public AMD64NewInstanceStubCallOp(Value result, Value hub, LIRFrameState state) {
+        this.result = result;
+        this.hub = hub;
+        this.temp = AMD64.rax.asValue(Kind.Object);
+        this.state = state;
     }
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        Value result = output(0);
-        Value hub = input(0);
-
         // rdx: (in) hub
         // rax: (out) result
-        assert asRegister(hub) == AMD64.rdx;
-        AMD64Call.directCall(tasm, masm, HotSpotGraalRuntime.getInstance().getConfig().newInstanceStub, info);
+        AMD64Call.directCall(tasm, masm, HotSpotGraalRuntime.getInstance().getConfig().newInstanceStub, state);
         if (asRegister(result) != AMD64.rax) {
             masm.movq(asRegister(result), AMD64.rax);
         }
     }
 
     @Override
-    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-        if (mode == OperandMode.Input) {
-            return EnumSet.of(OperandFlag.Register);
-        } else if (mode == OperandMode.Output) {
-            return EnumSet.of(OperandFlag.Register);
-        } else if (mode == OperandMode.Temp) {
-            return EnumSet.of(OperandFlag.Register);
-        }
-        throw GraalInternalError.shouldNotReachHere();
+    protected void verify() {
+        super.verify();
+        assert asRegister(hub) == AMD64.rdx;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/AMD64VerifyOopStubCallOp.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/AMD64VerifyOopStubCallOp.java	Mon Jul 02 18:20:25 2012 +0200
@@ -24,13 +24,10 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.max.asm.target.amd64.*;
@@ -38,30 +35,26 @@
 /**
  * A call to HotSpot's object pointer verification stub.
  */
+@Opcode("VERIFY_OOP")
 public class AMD64VerifyOopStubCallOp extends AMD64LIRInstruction {
-    public AMD64VerifyOopStubCallOp(Value object, LIRDebugInfo info) {
-        super("VERIFY_OOP", LIRInstruction.NO_OPERANDS, info, new Value[] {object}, NO_OPERANDS, NO_OPERANDS);
+    @Use protected Value object;
+    @State protected LIRFrameState state;
+
+    public AMD64VerifyOopStubCallOp(Value object, LIRFrameState state) {
+        this.object = object;
+        this.state = state;
     }
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        Register object = asRegister(input(0));
         // r13: (in) object
-        if (object != AMD64.r13) {
+        if (asRegister(object) != AMD64.r13) {
             masm.push(AMD64.r13);
-            masm.movq(AMD64.r13, object);
+            masm.movq(AMD64.r13, asRegister(object));
         }
-        AMD64Call.directCall(tasm, masm, HotSpotGraalRuntime.getInstance().getConfig().verifyOopStub, info);
-        if (object != AMD64.r13) {
+        AMD64Call.directCall(tasm, masm, HotSpotGraalRuntime.getInstance().getConfig().verifyOopStub, state);
+        if (asRegister(object) != AMD64.r13) {
             masm.pop(AMD64.r13);
         }
     }
-
-    @Override
-    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-        if (mode == OperandMode.Input) {
-            return EnumSet.of(OperandFlag.Register);
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64SafepointOp.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64SafepointOp.java	Mon Jul 02 18:20:25 2012 +0200
@@ -25,12 +25,10 @@
 import static com.oracle.graal.hotspot.meta.HotSpotXirGenerator.*;
 import static com.oracle.max.asm.target.amd64.AMD64.*;
 
-import java.util.*;
-
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.max.asm.target.amd64.*;
@@ -38,12 +36,14 @@
 /**
  * Emits a safepoint poll.
  */
+@Opcode("SAFEPOINT")
 public class AMD64SafepointOp extends AMD64LIRInstruction {
+    @State protected LIRFrameState state;
 
     private final HotSpotVMConfig config;
 
-    public AMD64SafepointOp(LIRDebugInfo info, HotSpotVMConfig config) {
-        super("SAFEPOINT", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+    public AMD64SafepointOp(LIRFrameState state, HotSpotVMConfig config) {
+        this.state = state;
         this.config = config;
     }
 
@@ -54,17 +54,12 @@
         if (config.isPollingPageFar) {
             asm.movq(scratch, config.safepointPollingAddress);
             tasm.recordMark(MARK_POLL_FAR);
-            tasm.recordSafepoint(pos, info);
+            tasm.recordSafepoint(pos, state);
             asm.movq(scratch, new Address(tasm.target.wordKind, scratch.asValue()));
         } else {
             tasm.recordMark(MARK_POLL_NEAR);
-            tasm.recordSafepoint(pos, info);
+            tasm.recordSafepoint(pos, state);
             asm.movq(scratch, new Address(tasm.target.wordKind, rip.asValue()));
         }
     }
-
-    @Override
-    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-        throw GraalInternalError.shouldNotReachHere();
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64TailcallOp.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64TailcallOp.java	Mon Jul 02 18:20:25 2012 +0200
@@ -26,33 +26,23 @@
 
 import java.util.*;
 
-import com.oracle.max.asm.target.amd64.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
 
 /**
  * Performs a hard-coded tail call to the specified target, which normally should be an RiCompiledCode instance.
  */
+@Opcode("TAILCALL")
 public class AMD64TailcallOp extends AMD64LIRInstruction {
-
-    public AMD64TailcallOp(List<Value> parameters, Value target, Value[] callingConvention) {
-        super("TAILCALL", LIRInstruction.NO_OPERANDS, null, toArray(parameters, target), LIRInstruction.NO_OPERANDS, callingConvention.clone());
-        assert inputs.length == temps.length + 1;
+    @Use protected Value target;
+    @Alive protected Value[] parameters;
 
-        for (int i = 0; i < temps.length; i++) {
-            assert isRegister(temps[i]) : "too many parameters for tail call";
-            assert sameRegister(temps[i], inputs[i]) : "inputs do not match calling convention";
-        }
-    }
-
-    private static Value[] toArray(List<Value> parameters, Value target) {
-        Value[] result = new Value[parameters.size() + 1];
-        parameters.toArray(result);
-        result[parameters.size()] = target;
-        return result;
+    public AMD64TailcallOp(List<Value> parameters, Value target) {
+        this.target = target;
+        this.parameters = parameters.toArray(new Value[parameters.size()]);
     }
 
     @Override
@@ -61,17 +51,7 @@
         masm.leave();
 
         // jump to the target method
-        masm.jmp(asRegister(inputs[inputs.length - 1]));
+        masm.jmp(asRegister(target));
         masm.ensureUniquePC();
     }
-
-    @Override
-    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-        if (mode == OperandMode.Input) {
-            return EnumSet.of(OperandFlag.Register);
-        } else if (mode == OperandMode.Temp) {
-            return EnumSet.of(OperandFlag.Register);
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Mon Jul 02 18:20:25 2012 +0200
@@ -61,7 +61,7 @@
 
             @Override
             public void visitSafepointNode(SafepointNode i) {
-                LIRDebugInfo info = state();
+                LIRFrameState info = state();
                 append(new AMD64SafepointOp(info, ((HotSpotRuntime) runtime).config));
             }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Mon Jul 02 18:20:25 2012 +0200
@@ -23,16 +23,15 @@
 package com.oracle.graal.lir.amd64;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-
-import java.util.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.max.asm.*;
-import com.oracle.max.asm.target.amd64.*;
-import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.*;
+import com.oracle.max.asm.target.amd64.*;
+import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag;
 
 public enum AMD64Arithmetic {
     IADD, ISUB, IMUL, IDIV, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR,
@@ -48,254 +47,183 @@
 
 
     public static class Op1Reg extends AMD64LIRInstruction {
-        public Op1Reg(AMD64Arithmetic opcode, Value result, Value x) {
-            super(opcode, new Value[] {result}, null, new Value[] {x}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
-        }
-
-        @Override
-        public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Value result = output(0);
-            Value x = input(0);
-
-            emit(tasm, masm, (AMD64Arithmetic) code, result, x, null);
-        }
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG}) protected Value x;
 
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public static class Op1Stack extends AMD64LIRInstruction {
-        public Op1Stack(AMD64Arithmetic opcode, Value result, Value x) {
-            super(opcode, new Value[] {result}, null, new Value[] {x}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+        public Op1Reg(AMD64Arithmetic opcode, Value result, Value x) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Value result = output(0);
-            Value x = input(0);
-
-            AMD64Move.move(tasm, masm, result, x);
-            emit(tasm, masm, (AMD64Arithmetic) code, result);
-        }
-
-        @Override
-        public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            emit(tasm, masm, opcode, result, x, null);
         }
     }
 
-    public static class Op2Stack extends AMD64LIRInstruction {
-        public Op2Stack(AMD64Arithmetic opcode, Value result, Value x, Value y) {
-            super(opcode, new Value[] {result}, null, new Value[] {x}, new Value[] {y}, LIRInstruction.NO_OPERANDS);
+    public static class Op1Stack extends AMD64LIRInstruction {
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value x;
+
+        public Op1Stack(AMD64Arithmetic opcode, Value result, Value x) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Value result = output(0);
-            Value x = input(0);
-            Value y = alive(0);
-
             AMD64Move.move(tasm, masm, result, x);
-            emit(tasm, masm, (AMD64Arithmetic) code, result, y, null);
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            } else if (mode == OperandMode.Alive && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public void verify() {
-            Value result = output(0);
-            Value x = input(0);
-            Value y = alive(0);
-
-            super.verify();
-            assert differentRegisters(result, y) || sameRegister(x, y);
-            verifyKind((AMD64Arithmetic) code, result, x, y);
+            emit(tasm, masm, opcode, result);
         }
     }
 
-    public static class Op2Reg extends AMD64LIRInstruction {
-        public Op2Reg(AMD64Arithmetic opcode, Value result, Value x, Value y) {
-            super(opcode, new Value[] {result}, null, new Value[] {x}, new Value[] {y}, LIRInstruction.NO_OPERANDS);
+    public static class Op2Stack extends AMD64LIRInstruction {
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value x;
+        @Alive({REG, STACK, CONST}) protected Value y;
+
+        public Op2Stack(AMD64Arithmetic opcode, Value result, Value x, Value y) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.y = y;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Value result = output(0);
-            Value x = input(0);
-            Value y = alive(0);
-
             AMD64Move.move(tasm, masm, result, x);
-            emit(tasm, masm, (AMD64Arithmetic) code, result, y, null);
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            } else if (mode == OperandMode.Alive && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Constant);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            emit(tasm, masm, opcode, result, y, null);
         }
 
         @Override
         public void verify() {
-            Value result = output(0);
-            Value x = input(0);
-            Value y = alive(0);
-
             super.verify();
             assert differentRegisters(result, y) || sameRegister(x, y);
-            verifyKind((AMD64Arithmetic) code, result, x, y);
+            verifyKind(opcode, result, x, y);
+        }
+    }
+
+    public static class Op2Reg extends AMD64LIRInstruction {
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value x;
+        @Alive({REG, CONST}) protected Value y;
+
+        public Op2Reg(AMD64Arithmetic opcode, Value result, Value x, Value y) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+            AMD64Move.move(tasm, masm, result, x);
+            emit(tasm, masm, opcode, result, y, null);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert differentRegisters(result, y) || sameRegister(x, y);
+            verifyKind(opcode, result, x, y);
         }
     }
 
     public static class Op2RegCommutative extends AMD64LIRInstruction {
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value x;
+        @Use({REG, CONST}) protected Value y;
+
         public Op2RegCommutative(AMD64Arithmetic opcode, Value result, Value x, Value y) {
-            super(opcode, new Value[] {result}, null, new Value[] {x, y}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.y = y;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Value result = output(0);
-            Value x = input(0);
-            Value y = input(1);
-
             if (sameRegister(result, y)) {
-                emit(tasm, masm, (AMD64Arithmetic) code, result, x, null);
+                emit(tasm, masm, opcode, result, x, null);
             } else {
                 AMD64Move.move(tasm, masm, result, x);
-                emit(tasm, masm, (AMD64Arithmetic) code, result, y, null);
+                emit(tasm, masm, opcode, result, y, null);
             }
         }
 
         @Override
-        public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            } else if (mode == OperandMode.Input && index == 1) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Constant);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        @Override
         protected void verify() {
-            Value result = output(0);
-            Value x = input(0);
-            Value y = input(1);
-
             super.verify();
-            verifyKind((AMD64Arithmetic) code, result, x, y);
+            verifyKind(opcode, result, x, y);
         }
     }
 
     public static class ShiftOp extends AMD64LIRInstruction {
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value x;
+        @Alive({REG, CONST}) protected Value y;
+
         public ShiftOp(AMD64Arithmetic opcode, Value result, Value x, Value y) {
-            super(opcode, new Value[] {result}, null, new Value[] {x}, new Value[] {y}, LIRInstruction.NO_OPERANDS);
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.y = y;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Value result = output(0);
-            Value x = input(0);
-            Value y = alive(0);
-
             AMD64Move.move(tasm, masm, result, x);
-            emit(tasm, masm, (AMD64Arithmetic) code, result, y, null);
-        }
-
-        @Override
-        public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            } else if (mode == OperandMode.Alive && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Constant);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            emit(tasm, masm, opcode, result, y, null);
         }
 
         @Override
         public void verify() {
-            Value result = output(0);
-            Value x = input(0);
-            Value y = alive(0);
-
             super.verify();
             assert isConstant(y) || asRegister(y) == AMD64.rcx;
             assert differentRegisters(result, y) || sameRegister(x, y);
-            verifyKind((AMD64Arithmetic) code, result, x, x);
+            verifyKind(opcode, result, x, x);
             assert y.kind.stackKind() == Kind.Int;
         }
     }
 
     public static class DivOp extends AMD64LIRInstruction {
-        public DivOp(AMD64Arithmetic opcode, Value result, Value x, Value y, LIRDebugInfo info) {
-            super(opcode, new Value[] {result}, info, new Value[] {x}, new Value[] {y}, new Value[] {asRegister(result) == AMD64.rax ? AMD64.rdx.asValue(result.kind) : AMD64.rax.asValue(result.kind)});
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def protected Value result;
+        @Use protected Value x;
+        @Alive protected Value y;
+        @Temp protected Value temp;
+        @State protected LIRFrameState state;
+
+        public DivOp(AMD64Arithmetic opcode, Value result, Value x, Value y, LIRFrameState state) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.y = y;
+            this.temp = asRegister(result) == AMD64.rax ? AMD64.rdx.asValue(result.kind) : AMD64.rax.asValue(result.kind);
+            this.state = state;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Value result = output(0);
-            Value y = alive(0);
-
-            emit(tasm, masm, (AMD64Arithmetic) code, result, y, info);
-        }
-
-        @Override
-        public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Alive && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Temp && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            emit(tasm, masm, opcode, result, y, state);
         }
 
         @Override
         protected void verify() {
-            Value result = output(0);
-            Value x = input(0);
-            Value y = alive(0);
-
             super.verify();
             // left input in rax, right input in any register but rax and rdx, result quotient in rax, result remainder in rdx
             assert asRegister(x) == AMD64.rax;
             assert differentRegisters(y, AMD64.rax.asValue(), AMD64.rdx.asValue());
             assert (name().endsWith("DIV") && asRegister(result) == AMD64.rax) || (name().endsWith("REM") && asRegister(result) == AMD64.rdx);
-            verifyKind((AMD64Arithmetic) code, result, x, y);
+            verifyKind(opcode, result, x, y);
         }
     }
 
@@ -313,7 +241,7 @@
         }
     }
 
-    public static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, Value dst, Value src, LIRDebugInfo info) {
+    public static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, Value dst, Value src, LIRFrameState info) {
         int exceptionOffset = -1;
         if (isRegister(src)) {
             switch (opcode) {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Mon Jul 02 18:20:25 2012 +0200
@@ -23,27 +23,35 @@
 package com.oracle.graal.lir.amd64;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import java.util.*;
 
+import com.oracle.graal.api.code.CompilationResult.Mark;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.cri.xir.CiXirAssembler.XirMark;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.CompilationResult.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
 
 public class AMD64Call {
 
+    @Opcode("CALL_DIRECT")
     public static class DirectCallOp extends AMD64LIRInstruction implements StandardOp.CallOp {
-        private final Object targetMethod;
-        private final Map<XirMark, Mark> marks;
+        @Def({REG, ILLEGAL}) protected Value result;
+        @Use({REG, STACK}) protected Value[] parameters;
+        @State protected LIRFrameState state;
 
-        public DirectCallOp(Object targetMethod, Value result, Value[] parameters, LIRDebugInfo info, Map<XirMark, Mark> marks) {
-            super("CALL_DIRECT", new Value[] {result}, info, parameters, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+        protected final Object targetMethod;
+        protected final Map<XirMark, Mark> marks;
+
+        public DirectCallOp(Object targetMethod, Value result, Value[] parameters, LIRFrameState state, Map<XirMark, Mark> marks) {
             this.targetMethod = targetMethod;
+            this.result = result;
+            this.parameters = parameters;
+            this.state = state;
             this.marks = marks;
         }
 
@@ -53,57 +61,36 @@
             if (marks != null) {
                 marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0]));
             }
-            directCall(tasm, masm, targetMethod, info);
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
-            } else if (mode == OperandMode.Output) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            directCall(tasm, masm, targetMethod, state);
         }
     }
 
+    @Opcode("CALL_INDIRECT")
     public static class IndirectCallOp extends AMD64LIRInstruction implements StandardOp.CallOp {
+        @Def({REG, ILLEGAL}) protected Value result;
+        @Use({REG, STACK}) protected Value[] parameters;
+        @Use({REG}) protected Value targetAddress;
+        @State protected LIRFrameState state;
+
         private final Object targetMethod;
         private final Map<XirMark, Mark> marks;
 
-        private static Value[] concat(Value[] parameters, Value targetAddress) {
-            Value[] result = Arrays.copyOf(parameters, parameters.length + 1);
-            result[result.length - 1] = targetAddress;
-            return result;
-        }
-
-        public IndirectCallOp(Object targetMethod, Value result, Value[] parameters, Value targetAddress, LIRDebugInfo info, Map<XirMark, Mark> marks) {
-            super("CALL_INDIRECT", new Value[] {result}, info, concat(parameters, targetAddress), LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+        public IndirectCallOp(Object targetMethod, Value result, Value[] parameters, Value targetAddress, LIRFrameState state, Map<XirMark, Mark> marks) {
             this.targetMethod = targetMethod;
+            this.result = result;
+            this.parameters = parameters;
+            this.targetAddress = targetAddress;
+            this.state = state;
             this.marks = marks;
         }
 
-        private Value targetAddress() {
-            return input(inputs.length - 1);
-        }
-
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
             callAlignment(tasm, masm);
             if (marks != null) {
                 marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0]));
             }
-            indirectCall(tasm, masm, asRegister(targetAddress()), targetMethod, info);
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
-            } else if (mode == OperandMode.Output) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            indirectCall(tasm, masm, asRegister(targetAddress), targetMethod, state);
         }
     }
 
@@ -117,7 +104,7 @@
         }
     }
 
-    public static void directCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object target, LIRDebugInfo info) {
+    public static void directCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object target, LIRFrameState info) {
         int before = masm.codeBuffer.position();
         if (target instanceof RuntimeCall) {
             long maxOffset = tasm.runtime.getMaxCallTargetOffset((RuntimeCall) target);
@@ -148,7 +135,7 @@
         masm.ensureUniquePC();
     }
 
-    public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register dst, Object target, LIRDebugInfo info) {
+    public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Register dst, Object target, LIRFrameState info) {
         int before = masm.codeBuffer.position();
         masm.call(dst);
         int after = masm.codeBuffer.position();
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Mon Jul 02 18:20:25 2012 +0200
@@ -23,45 +23,34 @@
 package com.oracle.graal.lir.amd64;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import java.util.*;
-
-import com.oracle.max.asm.target.amd64.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
 
 public enum AMD64Compare {
     ICMP, LCMP, ACMP, FCMP, DCMP;
 
     public static class CompareOp extends AMD64LIRInstruction {
+        @Opcode private final AMD64Compare opcode;
+        @Use({REG}) protected Value x;
+        @Use({REG, STACK, CONST}) protected Value y;
+
         public CompareOp(AMD64Compare opcode, Value x, Value y) {
-            super(opcode, LIRInstruction.NO_OPERANDS, null, new Value[] {x, y}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            this.opcode = opcode;
+            this.x = x;
+            this.y = y;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Value x = input(0);
-            Value y = input(1);
-            emit(tasm, masm, (AMD64Compare) code, x, y);
-        }
-
-        @Override
-        public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Input && index == 1) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            emit(tasm, masm, opcode, x, y);
         }
 
         @Override
         protected void verify() {
-            Value x = input(0);
-            Value y = input(1);
-
             super.verify();
             assert (name().startsWith("I") && x.kind == Kind.Int && y.kind.stackKind() == Kind.Int)
                 || (name().startsWith("I") && x.kind == Kind.Jsr && y.kind == Kind.Jsr)
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Mon Jul 02 18:20:25 2012 +0200
@@ -23,27 +23,29 @@
 package com.oracle.graal.lir.amd64;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import java.util.*;
-
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.Address.Scale;
+import com.oracle.graal.api.code.CompilationResult.JumpTable;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.StandardOp.FallThroughOp;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.max.asm.*;
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Address.*;
-import com.oracle.graal.api.code.CompilationResult.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.FallThroughOp;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.calc.*;
 
 public class AMD64ControlFlow {
 
     public static class ReturnOp extends AMD64LIRInstruction {
-        public ReturnOp(Value input) {
-            super("RETURN", LIRInstruction.NO_OPERANDS, null, new Value[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+        @Use({REG, ILLEGAL}) protected Value x;
+
+        public ReturnOp(Value x) {
+            this.x = x;
         }
 
         @Override
@@ -53,29 +55,22 @@
             }
             masm.ret(0);
         }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
     }
 
 
     public static class BranchOp extends AMD64LIRInstruction implements StandardOp.BranchOp {
         protected ConditionFlag condition;
         protected LabelRef destination;
+        @State protected LIRFrameState state;
 
-        public BranchOp(Condition condition, LabelRef destination, LIRDebugInfo info) {
+        public BranchOp(Condition condition, LabelRef destination, LIRFrameState info) {
             this(intCond(condition), destination, info);
         }
 
-        public BranchOp(ConditionFlag condition, LabelRef destination, LIRDebugInfo info) {
-            super("BRANCH", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+        public BranchOp(ConditionFlag condition, LabelRef destination, LIRFrameState state) {
             this.condition = condition;
             this.destination = destination;
+            this.state = state;
         }
 
         @Override
@@ -93,23 +88,13 @@
             destination = newDestination;
             condition = condition.negate();
         }
-
-        @Override
-        public String operationString() {
-            return condition.operator + " [" + destination + "]";
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
     }
 
 
     public static class FloatBranchOp extends BranchOp {
         protected boolean unorderedIsTrue;
 
-        public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef destination, LIRDebugInfo info) {
+        public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef destination, LIRFrameState info) {
             super(floatCond(condition), destination, info);
             this.unorderedIsTrue = unorderedIsTrue;
         }
@@ -124,11 +109,6 @@
             super.negate(newDestination);
             unorderedIsTrue = !unorderedIsTrue;
         }
-
-        @Override
-        public String operationString() {
-            return condition.operator + " [" + destination + "]" + (unorderedIsTrue ? " unorderedIsTrue" : " unorderedIsFalse");
-        }
     }
 
 
@@ -136,58 +116,41 @@
         private final int lowKey;
         private final LabelRef defaultTarget;
         private final LabelRef[] targets;
+        @Alive protected Value index;
+        @Temp protected Value scratch;
 
         public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) {
-            super("TABLE_SWITCH", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, new Value[] {index}, new Value[] {scratch});
             this.lowKey = lowKey;
             this.defaultTarget = defaultTarget;
             this.targets = targets;
+            this.index = index;
+            this.scratch = scratch;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            tableswitch(tasm, masm, lowKey, defaultTarget, targets, asIntReg(alive(0)), asLongReg(temp(0)));
-        }
-
-        @Override
-        public String operationString() {
-            StringBuilder buf = new StringBuilder(super.operationString());
-            buf.append("\ndefault: [").append(defaultTarget).append(']');
-            int key = lowKey;
-            for (LabelRef l : targets) {
-                buf.append("\ncase ").append(key).append(": [").append(l).append(']');
-                key++;
-            }
-            return buf.toString();
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Alive && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Temp && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            tableswitch(tasm, masm, lowKey, defaultTarget, targets, asIntReg(index), asLongReg(scratch));
         }
     }
 
     public static class SequentialSwitchOp extends AMD64LIRInstruction implements FallThroughOp {
-        private final Constant[] keyConstants;
+        @Use({CONST}) protected Constant[] keyConstants;
         private final LabelRef[] keyTargets;
         private LabelRef defaultTarget;
+        @Alive({REG}) protected Value key;
+        @Temp({REG, ILLEGAL}) protected Value scratch;
 
-        public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value... temp) {
-            super("SEQUENTIAL_SWITCH", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, new Value[] {key}, temp);
+        public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
             assert keyConstants.length == keyTargets.length;
             this.keyConstants = keyConstants;
             this.keyTargets = keyTargets;
             this.defaultTarget = defaultTarget;
+            this.key = key;
+            this.scratch = scratch;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Value key = alive(0);
             if (key.kind == Kind.Int) {
                 Register intKey = asIntReg(key);
                 for (int i = 0; i < keyConstants.length; i++) {
@@ -196,7 +159,7 @@
                 }
             } else if (key.kind == Kind.Object) {
                 Register intKey = asObjectReg(key);
-                Register temp = asObjectReg(temp(0));
+                Register temp = asObjectReg(scratch);
                 for (int i = 0; i < keyConstants.length; i++) {
                     AMD64Move.move(tasm, masm, temp.asValue(Kind.Object), keyConstants[i]);
                     masm.cmpptr(intKey, temp);
@@ -213,26 +176,6 @@
         }
 
         @Override
-        public String operationString() {
-            StringBuilder buf = new StringBuilder(super.operationString());
-            buf.append("\ndefault: [").append(defaultTarget).append(']');
-            for (int i = 0; i < keyConstants.length; i++) {
-                buf.append("\ncase ").append(keyConstants[i]).append(": [").append(keyTargets[i]).append("]");
-            }
-            return buf.toString();
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Alive && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Temp && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        @Override
         public LabelRef fallThroughTarget() {
             return defaultTarget;
         }
@@ -248,37 +191,34 @@
         private LabelRef defaultTarget;
         private final int[] lowKeys;
         private final int[] highKeys;
+        @Alive protected Value key;
 
         public SwitchRangesOp(int[] lowKeys, int[] highKeys, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
-            super("SWITCH_RANGES", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, new Value[] {key}, LIRInstruction.NO_OPERANDS);
-            assert lowKeys.length == keyTargets.length;
-            assert highKeys.length == keyTargets.length;
-            assert key.kind == Kind.Int;
             this.lowKeys = lowKeys;
             this.highKeys = highKeys;
             this.keyTargets = keyTargets;
             this.defaultTarget = defaultTarget;
+            this.key = key;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            Register key = asIntReg(alive(0));
             for (int i = 0; i < lowKeys.length; i++) {
                 int lowKey = lowKeys[i];
                 int highKey = highKeys[i];
                 if (lowKey == highKey) {
-                    masm.cmpl(key, lowKey);
+                    masm.cmpl(asIntReg(key), lowKey);
                     masm.jcc(ConditionFlag.equal, keyTargets[i].label());
                 } else if (lowKey + 1 == highKey) {
-                    masm.cmpl(key, lowKey);
+                    masm.cmpl(asIntReg(key), lowKey);
                     masm.jcc(ConditionFlag.equal, keyTargets[i].label());
-                    masm.cmpl(key, highKey);
+                    masm.cmpl(asIntReg(key), highKey);
                     masm.jcc(ConditionFlag.equal, keyTargets[i].label());
                 } else {
                     Label skip = new Label();
-                    masm.cmpl(key, lowKey);
+                    masm.cmpl(asIntReg(key), lowKey);
                     masm.jcc(ConditionFlag.less, skip);
-                    masm.cmpl(key, highKey);
+                    masm.cmpl(asIntReg(key), highKey);
                     masm.jcc(ConditionFlag.lessEqual, keyTargets[i].label());
                     masm.bind(skip);
                 }
@@ -291,23 +231,11 @@
         }
 
         @Override
-        public String operationString() {
-            StringBuilder buf = new StringBuilder(super.operationString());
-            buf.append("\ndefault: [").append(defaultTarget).append(']');
-            for (int i = 0; i < lowKeys.length; i++) {
-                buf.append("\ncase ").append(lowKeys[i]).append(" - ").append(highKeys[i]).append(": [").append(keyTargets[i]).append("]");
-            }
-            return buf.toString();
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Alive && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Temp && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+        protected void verify() {
+            super.verify();
+            assert lowKeys.length == keyTargets.length;
+            assert highKeys.length == keyTargets.length;
+            assert key.kind == Kind.Int;
         }
 
         @Override
@@ -322,68 +250,46 @@
     }
 
 
+    @Opcode("CMOVE")
     public static class CondMoveOp extends AMD64LIRInstruction {
+        @Def({REG, HINT}) protected Value result;
+        @Alive({REG}) protected Value trueValue;
+        @Use({REG, STACK, CONST}) protected Value falseValue;
         private final ConditionFlag condition;
 
         public CondMoveOp(Variable result, Condition condition, Variable trueValue, Value falseValue) {
-            super("CMOVE", new Value[] {result}, null, new Value[] {falseValue}, new Value[] {trueValue}, LIRInstruction.NO_OPERANDS);
+            this.result = result;
             this.condition = intCond(condition);
+            this.trueValue = trueValue;
+            this.falseValue = falseValue;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            cmove(tasm, masm, output(0), false, condition, false, alive(0), input(0));
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            } else if (mode == OperandMode.Alive && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
-        @Override
-        public String operationString() {
-            return condition.toString() + " " + super.operationString();
+            cmove(tasm, masm, result, false, condition, false, trueValue, falseValue);
         }
     }
 
 
+    @Opcode("CMOVE")
     public static class FloatCondMoveOp extends AMD64LIRInstruction {
+        @Def({REG}) protected Value result;
+        @Alive({REG}) protected Value trueValue;
+        @Alive({REG}) protected Value falseValue;
         private final ConditionFlag condition;
         private final boolean unorderedIsTrue;
 
         public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
-            super("FLOAT_CMOVE", new Value[] {result}, null, LIRInstruction.NO_OPERANDS, new Value[] {trueValue, falseValue}, LIRInstruction.NO_OPERANDS);
+            this.result = result;
             this.condition = floatCond(condition);
             this.unorderedIsTrue = unorderedIsTrue;
+            this.trueValue = trueValue;
+            this.falseValue = falseValue;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            cmove(tasm, masm, output(0), true, condition, unorderedIsTrue, alive(0), alive(1));
-        }
-
-        @Override
-        public String operationString() {
-            return condition.toString() + " unordered=" + unorderedIsTrue + " " + super.operationString();
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Alive && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Alive && index == 1) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            cmove(tasm, masm, result, true, condition, unorderedIsTrue, trueValue, falseValue);
         }
     }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64LIRInstruction.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64LIRInstruction.java	Mon Jul 02 18:20:25 2012 +0200
@@ -22,20 +22,14 @@
  */
 package com.oracle.graal.lir.amd64;
 
-import com.oracle.max.asm.target.amd64.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
 
 /**
  * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method.
  */
 public abstract class AMD64LIRInstruction extends LIRInstruction {
-
-    public AMD64LIRInstruction(Object opcode, Value[] outputs, LIRDebugInfo info, Value[] inputs, Value[] alives, Value[] temps) {
-        super(opcode, outputs, info, inputs, alives, temps);
-    }
-
     @Override
     public final void emitCode(TargetMethodAssembler tasm) {
         emitCode(tasm, (AMD64MacroAssembler) tasm.asm);
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Mon Jul 02 18:20:25 2012 +0200
@@ -23,25 +23,30 @@
 package com.oracle.graal.lir.amd64;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 import static java.lang.Double.*;
 import static java.lang.Float.*;
 
-import java.util.*;
-
-import com.oracle.max.asm.*;
-import com.oracle.max.asm.target.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.*;
+import com.oracle.graal.lir.LIRInstruction.Opcode;
+import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.*;
+import com.oracle.max.asm.target.amd64.*;
 
 public class AMD64Move {
 
+    @Opcode("MOVE")
     public static class SpillMoveOp extends AMD64LIRInstruction implements MoveOp {
+        @Def({REG, STACK}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value input;
+
         public SpillMoveOp(Value result, Value input) {
-            super("MOVE", new Value[] {result}, null, new Value[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            this.result = result;
+            this.input = input;
         }
 
         @Override
@@ -51,28 +56,23 @@
 
         @Override
         public Value getInput() {
-            return input(0);
+            return input;
         }
         @Override
         public Value getResult() {
-            return output(0);
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            return result;
         }
     }
 
 
+    @Opcode("MOVE")
     public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp {
+        @Def({REG, HINT}) protected Value result;
+        @Use({REG, STACK, CONST}) protected Value input;
+
         public MoveToRegOp(Value result, Value input) {
-            super("MOVE", new Value[] {result}, null, new Value[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            this.result = result;
+            this.input = input;
         }
 
         @Override
@@ -82,28 +82,23 @@
 
         @Override
         public Value getInput() {
-            return input(0);
+            return input;
         }
         @Override
         public Value getResult() {
-            return output(0);
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            return result;
         }
     }
 
 
+    @Opcode("MOVE")
     public static class MoveFromRegOp extends AMD64LIRInstruction implements MoveOp {
+        @Def({REG, STACK}) protected Value result;
+        @Use({REG, CONST, HINT}) protected Value input;
+
         public MoveFromRegOp(Value result, Value input) {
-            super("MOVE", new Value[] {result}, null, new Value[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            this.result = result;
+            this.input = input;
         }
 
         @Override
@@ -113,87 +108,63 @@
 
         @Override
         public Value getInput() {
-            return input(0);
+            return input;
         }
         @Override
         public Value getResult() {
-            return output(0);
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.RegisterHint);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            return result;
         }
     }
 
 
     public static class LoadOp extends AMD64LIRInstruction {
-        public LoadOp(Value result, Value address, LIRDebugInfo info) {
-            super("LOAD", new Value[] {result}, info, new Value[] {address}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+        @Def({REG}) protected Value result;
+        @Use({ADDR}) protected Value address;
+        @State protected LIRFrameState state;
+
+        public LoadOp(Value result, Value address, LIRFrameState state) {
+            this.result = result;
+            this.address = address;
+            this.state = state;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            load(tasm, masm, output(0), (Address) input(0), info);
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Address);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            load(tasm, masm, result, (Address) address, state);
         }
     }
 
 
     public static class StoreOp extends AMD64LIRInstruction {
-        public StoreOp(Value address, Value input, LIRDebugInfo info) {
-            super("STORE", LIRInstruction.NO_OPERANDS, info, new Value[] {address, input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+        @Use({ADDR}) protected Value address;
+        @Use({REG, CONST}) protected Value input;
+        @State protected LIRFrameState state;
+
+        public StoreOp(Value address, Value input, LIRFrameState state) {
+            this.address = address;
+            this.input = input;
+            this.state = state;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            store(tasm, masm, (Address) input(0), input(1), info);
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Address);
-            } else if (mode == OperandMode.Input && index == 1) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Constant);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            store(tasm, masm, (Address) address, input, state);
         }
     }
 
 
     public static class LeaOp extends AMD64LIRInstruction {
+        @Def({REG}) protected Value result;
+        @Use({ADDR, STACK, UNINITIALIZED}) protected Value address;
+
         public LeaOp(Value result, Value address) {
-            super("LEA", new Value[] {result}, null, new Value[] {address}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            this.result = result;
+            this.address = address;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            masm.leaq(asLongReg(output(0)), tasm.asAddress(input(0)));
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Address, OperandFlag.Stack, OperandFlag.Uninitialized);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            masm.leaq(asLongReg(result), tasm.asAddress(address));
         }
     }
 
@@ -202,7 +173,6 @@
         private final int barriers;
 
         public MembarOp(final int barriers) {
-            super("MEMBAR", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
             this.barriers = barriers;
         }
 
@@ -210,57 +180,43 @@
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
             masm.membar(barriers);
         }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
     }
 
 
     public static class NullCheckOp extends AMD64LIRInstruction {
-        public NullCheckOp(Variable input, LIRDebugInfo info) {
-            super("NULL_CHECK", LIRInstruction.NO_OPERANDS, info, new Value[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+        @Use protected Value input;
+        @State protected LIRFrameState state;
+
+        public NullCheckOp(Variable input, LIRFrameState state) {
+            this.input = input;
+            this.state = state;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            tasm.recordImplicitException(masm.codeBuffer.position(), info);
-            masm.nullCheck(asRegister(input(0)));
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            tasm.recordImplicitException(masm.codeBuffer.position(), state);
+            masm.nullCheck(asRegister(input));
         }
     }
 
 
+    @Opcode("CAS")
     public static class CompareAndSwapOp extends AMD64LIRInstruction {
+        @Def protected Value result;
+        @Use({ADDR}) protected Value address;
+        @Use protected Value cmpValue;
+        @Use protected Value newValue;
+
         public CompareAndSwapOp(Value result, Address address, Value cmpValue, Value newValue) {
-            super("CAS", new Value[] {result}, null, new Value[] {address, cmpValue, newValue}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            this.result = result;
+            this.address = address;
+            this.cmpValue = cmpValue;
+            this.newValue = newValue;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            compareAndSwap(tasm, masm, output(0), asAddress(input(0)), input(1), input(2));
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Input && index == 0) {
-                return EnumSet.of(OperandFlag.Address);
-            } else if (mode == OperandMode.Input && index == 1) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Input && index == 2) {
-                return EnumSet.of(OperandFlag.Register);
-            } else if (mode == OperandMode.Output && index == 0) {
-                return EnumSet.of(OperandFlag.Register);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+            compareAndSwap(tasm, masm, result, (Address) address, cmpValue, newValue);
         }
     }
 
@@ -404,7 +360,7 @@
     }
 
 
-    public static void load(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Address loadAddr, LIRDebugInfo info) {
+    public static void load(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Address loadAddr, LIRFrameState info) {
         if (info != null) {
             tasm.recordImplicitException(masm.codeBuffer.position(), info);
         }
@@ -422,7 +378,7 @@
         }
     }
 
-    public static void store(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Address storeAddr, Value input, LIRDebugInfo info) {
+    public static void store(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Address storeAddr, Value input, LIRFrameState info) {
         if (info != null) {
             tasm.recordImplicitException(masm.codeBuffer.position(), info);
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Mon Jul 02 18:20:25 2012 +0200
@@ -108,7 +108,7 @@
     public boolean hasDebugInfo() {
         for (Block b : linearScanOrder()) {
             for (LIRInstruction op : b.lir) {
-                if (op.info != null) {
+                if (op.hasState()) {
                     return true;
                 }
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRDebugInfo.java	Mon Jul 02 16:53:12 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +0,0 @@
-/*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
-
-/**
- * This class represents garbage collection and deoptimization information attached to a LIR instruction.
- */
-public class LIRDebugInfo {
-    public final BytecodeFrame topFrame;
-    private final VirtualObject[] virtualObjects;
-    private final List<StackSlot> pointerSlots;
-    public final LabelRef exceptionEdge;
-    private DebugInfo debugInfo;
-
-    public LIRDebugInfo(BytecodeFrame topFrame, VirtualObject[] virtualObjects, List<StackSlot> pointerSlots, LabelRef exceptionEdge) {
-        this.topFrame = topFrame;
-        this.virtualObjects = virtualObjects;
-        this.pointerSlots = pointerSlots;
-        this.exceptionEdge = exceptionEdge;
-    }
-
-    public boolean hasDebugInfo() {
-        return debugInfo != null;
-    }
-
-    public DebugInfo debugInfo() {
-        assert debugInfo != null : "debug info not allocated yet";
-        return debugInfo;
-    }
-
-    /**
-     * Iterates the frame state and calls the {@link ValueProcedure} for every variable.
-     *
-     * @param proc The procedure called for variables.
-     */
-    public void forEachState(ValueProcedure proc) {
-        for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
-            processValues(cur.values, proc);
-        }
-        if (virtualObjects != null) {
-            for (VirtualObject obj : virtualObjects) {
-                processValues(obj.values(), proc);
-            }
-        }
-    }
-
-    /**
-     * We filter out constant and illegal values ourself before calling the procedure, so {@link OperandFlag#Constant} and {@link OperandFlag#Illegal} need not be set.
-     */
-    private static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
-
-    private void processValues(Value[] values, ValueProcedure proc) {
-        for (int i = 0; i < values.length; i++) {
-            Value value = values[i];
-            if (value instanceof MonitorValue) {
-                MonitorValue monitor = (MonitorValue) value;
-                if (processed(monitor.getOwner())) {
-                    monitor.setOwner(proc.doValue(monitor.getOwner(), OperandMode.Alive, STATE_FLAGS));
-                }
-
-            } else if (processed(value)) {
-                values[i] = proc.doValue(value, OperandMode.Alive, STATE_FLAGS);
-            }
-        }
-    }
-
-    private boolean processed(Value value) {
-        if (isIllegal(value)) {
-            // Ignore dead local variables.
-            return false;
-        } else if (isConstant(value)) {
-            // Ignore constants, the register allocator does not need to see them.
-            return false;
-        } else if (isVirtualObject(value)) {
-            assert Arrays.asList(virtualObjects).contains(value);
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-
-    public void finish(BitSet registerRefMap, BitSet frameRefMap, FrameMap frameMap) {
-        debugInfo = new DebugInfo(topFrame, registerRefMap, frameRefMap);
-
-        // Add additional stack slots for outgoing method parameters.
-        if (pointerSlots != null) {
-            for (StackSlot v : pointerSlots) {
-                frameMap.setReference(v, registerRefMap, frameRefMap);
-            }
-        }
-    }
-
-
-    @Override
-    public String toString() {
-        return debugInfo != null ? debugInfo.toString() : topFrame.toString();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+
+/**
+ * This class represents garbage collection and deoptimization information attached to a LIR instruction.
+ */
+public class LIRFrameState {
+    public final BytecodeFrame topFrame;
+    private final VirtualObject[] virtualObjects;
+    private final List<StackSlot> pointerSlots;
+    public final LabelRef exceptionEdge;
+    private DebugInfo debugInfo;
+
+    public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, List<StackSlot> pointerSlots, LabelRef exceptionEdge) {
+        this.topFrame = topFrame;
+        this.virtualObjects = virtualObjects;
+        this.pointerSlots = pointerSlots;
+        this.exceptionEdge = exceptionEdge;
+    }
+
+    public boolean hasDebugInfo() {
+        return debugInfo != null;
+    }
+
+    public DebugInfo debugInfo() {
+        assert debugInfo != null : "debug info not allocated yet";
+        return debugInfo;
+    }
+
+    /**
+     * Iterates the frame state and calls the {@link ValueProcedure} for every variable.
+     *
+     * @param proc The procedure called for variables.
+     */
+    public void forEachState(ValueProcedure proc) {
+        for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
+            processValues(cur.values, proc);
+        }
+        if (virtualObjects != null) {
+            for (VirtualObject obj : virtualObjects) {
+                processValues(obj.values(), proc);
+            }
+        }
+    }
+
+    /**
+     * We filter out constant and illegal values ourself before calling the procedure, so {@link OperandFlag#CONST} and {@link OperandFlag#ILLEGAL} need not be set.
+     */
+    private static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
+
+    private void processValues(Value[] values, ValueProcedure proc) {
+        for (int i = 0; i < values.length; i++) {
+            Value value = values[i];
+            if (value instanceof MonitorValue) {
+                MonitorValue monitor = (MonitorValue) value;
+                if (processed(monitor.getOwner())) {
+                    monitor.setOwner(proc.doValue(monitor.getOwner(), OperandMode.ALIVE, STATE_FLAGS));
+                }
+
+            } else if (processed(value)) {
+                values[i] = proc.doValue(value, OperandMode.ALIVE, STATE_FLAGS);
+            }
+        }
+    }
+
+    private boolean processed(Value value) {
+        if (isIllegal(value)) {
+            // Ignore dead local variables.
+            return false;
+        } else if (isConstant(value)) {
+            // Ignore constants, the register allocator does not need to see them.
+            return false;
+        } else if (isVirtualObject(value)) {
+            assert Arrays.asList(virtualObjects).contains(value);
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+
+    public void finish(BitSet registerRefMap, BitSet frameRefMap, FrameMap frameMap) {
+        debugInfo = new DebugInfo(topFrame, registerRefMap, frameRefMap);
+
+        // Add additional stack slots for outgoing method parameters.
+        if (pointerSlots != null) {
+            for (StackSlot v : pointerSlots) {
+                frameMap.setReference(v, registerRefMap, frameRefMap);
+            }
+        }
+    }
+
+
+    @Override
+    public String toString() {
+        return debugInfo != null ? debugInfo.toString() : topFrame.toString();
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon Jul 02 18:20:25 2012 +0200
@@ -22,8 +22,10 @@
  */
 package com.oracle.graal.lir;
 
-import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandMode.*;
 
+import java.lang.annotation.*;
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
@@ -69,6 +71,11 @@
     }
 
 
+    public abstract static class StateProcedure {
+        protected abstract void doState(LIRFrameState state);
+    }
+
+
     /**
      * Constants denoting how a LIR instruction uses an operand.
      */
@@ -79,28 +86,64 @@
          * to a Temp or Output operand. The value can be used again after the instruction, so the instruction must not
          * modify the register.
          */
-        Input,
+        USE,
 
         /**
          * The value must have been defined before. It is alive before the instruction and throughout the instruction. A
          * register assigned to it cannot be assigned to a Temp or Output operand. The value can be used again after the
          * instruction, so the instruction must not modify the register.
          */
-        Alive,
+        ALIVE,
 
         /**
          * The value must not have been defined before, and must not be used after the instruction. The instruction can
          * do whatever it wants with the register assigned to it (or not use it at all).
          */
-        Temp,
+        TEMP,
 
         /**
          * The value must not have been defined before. The instruction has to assign a value to the register. The
          * value can (and most likely will) be used after the instruction.
          */
-        Output,
+        DEF,
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Use {
+        OperandFlag[] value() default REG;
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Alive {
+        OperandFlag[] value() default REG;
     }
 
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Temp {
+        OperandFlag[] value() default REG;
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Def {
+        OperandFlag[] value() default REG;
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface State {
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.TYPE, ElementType.FIELD})
+    public static @interface Opcode {
+        String value() default "";
+    }
+
+
     /**
      * Flags for an operand.
      */
@@ -108,83 +151,61 @@
         /**
          * The value can be a {@link RegisterValue}.
          */
-        Register,
+        REG,
 
         /**
          * The value can be a {@link StackSlot}.
          */
-        Stack,
+        STACK,
 
         /**
          * The value can be a {@link Address}.
          */
-        Address,
+        ADDR,
 
         /**
          * The value can be a {@link Constant}.
          */
-        Constant,
+        CONST,
 
         /**
          * The value can be {@link Value#IllegalValue}.
          */
-        Illegal,
+        ILLEGAL,
 
         /**
          * The register allocator should try to assign a certain register to improve code quality.
          * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints.
          */
-        RegisterHint,
+        HINT,
 
         /**
          * The value can be uninitialized, e.g., a stack slot that has not written to before. This is only
          * used to avoid false positives in verification code.
          */
-        Uninitialized,
+        UNINITIALIZED,
     }
 
+
     /**
      * For validity checking of the operand flags defined by instruction subclasses.
      */
-    private static final EnumMap<OperandMode, EnumSet<OperandFlag>> ALLOWED_FLAGS;
+    protected static final EnumMap<OperandMode, EnumSet<OperandFlag>> ALLOWED_FLAGS;
 
     static {
         ALLOWED_FLAGS = new EnumMap<>(OperandMode.class);
-        ALLOWED_FLAGS.put(OperandMode.Input,  EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Address, OperandFlag.Constant, OperandFlag.Illegal, OperandFlag.RegisterHint, OperandFlag.Uninitialized));
-        ALLOWED_FLAGS.put(OperandMode.Alive,  EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Address, OperandFlag.Constant, OperandFlag.Illegal, OperandFlag.RegisterHint, OperandFlag.Uninitialized));
-        ALLOWED_FLAGS.put(OperandMode.Temp,   EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.Illegal, OperandFlag.RegisterHint));
-        ALLOWED_FLAGS.put(OperandMode.Output, EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Illegal, OperandFlag.RegisterHint));
+        ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, ADDR, CONST, ILLEGAL, HINT, UNINITIALIZED));
+        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, ADDR, CONST, ILLEGAL, HINT, UNINITIALIZED));
+        ALLOWED_FLAGS.put(TEMP,  EnumSet.of(REG, CONST, ILLEGAL, HINT));
+        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, ILLEGAL, HINT));
     }
 
     /**
-     * The opcode of this instruction.
-     */
-    protected final Object code;
-
-    /**
-     * The output operands for this instruction (modified by the register allocator).
+     * The flags of the base and index value of an address.
      */
-    protected Value[] outputs;
-
-    /**
-     * The input operands for this instruction (modified by the register allocator).
-     */
-    protected Value[] inputs;
+    protected static final EnumSet<OperandFlag> ADDRESS_FLAGS = EnumSet.of(REG, ILLEGAL);
 
-    /**
-     * The alive operands for this instruction (modified by the register allocator).
-     */
-    protected Value[] alives;
-
-    /**
-     * The temp operands for this instruction (modified by the register allocator).
-     */
-    protected Value[] temps;
-
-    /**
-     * Used to emit debug information.
-     */
-    public final LIRDebugInfo info;
+    private final LIRInstructionClass instructionClass;
 
     /**
      * Instruction id for register allocation.
@@ -192,22 +213,11 @@
     private int id;
 
     /**
-     * Constructs a new LIR instruction that has input and temp operands.
-     *
-     * @param opcode the opcode of the new instruction
-     * @param outputs the operands that holds the operation results of this instruction.
-     * @param info the {@link LIRDebugInfo} info that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction.
-     * @param inputs the input operands for the instruction.
-     * @param temps the temp operands for the instruction.
+     * Constructs a new LIR instruction.
      */
-    public LIRInstruction(Object opcode, Value[] outputs, LIRDebugInfo info, Value[] inputs, Value[] alives, Value[] temps) {
-        this.code = opcode;
-        this.outputs = outputs;
-        this.inputs = inputs;
-        this.alives = alives;
-        this.temps = temps;
-        this.info = info;
-        this.id = -1;
+    public LIRInstruction() {
+        instructionClass = LIRInstructionClass.get(getClass());
+        id = -1;
     }
 
     public abstract void emitCode(TargetMethodAssembler tasm);
@@ -222,100 +232,18 @@
     }
 
     /**
-     * Gets an input operand of this instruction.
-     *
-     * @param index the index of the operand requested.
-     * @return the {@code index}'th input operand.
-     */
-    protected final Value input(int index) {
-        return inputs[index];
-    }
-
-    /**
-     * Gets an alive operand of this instruction.
-     *
-     * @param index the index of the operand requested.
-     * @return the {@code index}'th alive operand.
-     */
-    protected final Value alive(int index) {
-        return alives[index];
-    }
-
-    /**
-     * Gets a temp operand of this instruction.
-     *
-     * @param index the index of the operand requested.
-     * @return the {@code index}'th temp operand.
-     */
-    protected final Value temp(int index) {
-        return temps[index];
-    }
-
-    /**
-     * Gets the result operand for this instruction.
-     *
-     * @return return the result operand
-     */
-    protected final Value output(int index) {
-        return outputs[index];
-    }
-
-    /**
      * Gets the instruction name.
      */
-    public String name() {
-        return code.toString();
+    public final String name() {
+        return instructionClass.getOpcode(this);
     }
 
-    public boolean hasOperands() {
-        return inputs.length > 0 || alives.length > 0 || temps.length > 0 || outputs.length > 0 || info != null || hasCall();
-    }
-
-    private static final EnumSet<OperandFlag> ADDRESS_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
-
-    private void forEach(Value[] values, OperandMode mode, ValueProcedure proc) {
-        for (int i = 0; i < values.length; i++) {
-            assert ALLOWED_FLAGS.get(mode).containsAll(flagsFor(mode, i));
-
-            Value value = values[i];
-            if (isAddress(value)) {
-                assert flagsFor(mode, i).contains(OperandFlag.Address);
-                Address address = asAddress(value);
-                address.setBase(proc.doValue(address.getBase(), mode, ADDRESS_FLAGS));
-                address.setIndex(proc.doValue(address.getIndex(), mode, ADDRESS_FLAGS));
-            } else {
-                values[i] = proc.doValue(values[i], mode, flagsFor(mode, i));
-            }
-        }
+    public final boolean hasOperands() {
+        return instructionClass.hasOperands() || hasState() || hasCall();
     }
 
-    public final void forEachInput(ValueProcedure proc) {
-        forEach(inputs, OperandMode.Input, proc);
-    }
-
-    public final void forEachAlive(ValueProcedure proc) {
-        forEach(alives, OperandMode.Alive, proc);
-    }
-
-    public final void forEachTemp(ValueProcedure proc) {
-        forEach(temps, OperandMode.Temp, proc);
-    }
-
-    public final void forEachOutput(ValueProcedure proc) {
-        forEach(outputs, OperandMode.Output, proc);
-    }
-
-    public final void forEachState(ValueProcedure proc) {
-        if (info != null) {
-            info.forEachState(proc);
-
-            if (this instanceof LIRXirInstruction) {
-                LIRXirInstruction xir = (LIRXirInstruction) this;
-                if (xir.infoAfter != null) {
-                    xir.infoAfter.forEachState(proc);
-                }
-            }
-        }
+    public final boolean hasState() {
+        return instructionClass.hasState(this);
     }
 
     /**
@@ -325,6 +253,31 @@
         return this instanceof StandardOp.CallOp;
     }
 
+
+    public final void forEachInput(ValueProcedure proc) {
+        instructionClass.forEachUse(this, proc);
+    }
+
+    public final void forEachAlive(ValueProcedure proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
+
+    public final void forEachTemp(ValueProcedure proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
+
+    public final void forEachOutput(ValueProcedure proc) {
+        instructionClass.forEachDef(this, proc);
+    }
+
+    public final void forEachState(ValueProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
+
+    public final void forEachState(StateProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
+
     /**
      * Iterates all register hints for the specified value, i.e., all preferred candidates for the register to be
      * assigned to the value.
@@ -339,32 +292,9 @@
      * @return The non-null value returned by the procedure, or null.
      */
     public Value forEachRegisterHint(Value value, OperandMode mode, ValueProcedure proc) {
-        Value[] hints;
-        if (mode == OperandMode.Input) {
-            hints = outputs;
-        } else if (mode == OperandMode.Output) {
-            hints = inputs;
-        } else {
-            return null;
-        }
-
-        for (int i = 0; i < hints.length; i++) {
-            Value result = proc.doValue(hints[i], null, null);
-            if (result != null) {
-                return result;
-            }
-        }
-        return null;
+        return instructionClass.forEachRegisterHint(this, mode, proc);
     }
 
-    /**
-     * Used by the register allocator to decide which kind of location can be assigned to the operand.
-     * @param mode The kind of operand.
-     * @param index The index of the operand.
-     * @return The flags for the operand.
-     */
-    // TODO (cwimmer) this method will go away when we have named operands, the flags will be specified as annotations instead.
-    protected abstract EnumSet<OperandFlag> flagsFor(OperandMode mode, int index);
 
     protected void verify() {
     }
@@ -377,72 +307,8 @@
         return "     " + toString();
     }
 
-    /**
-     * Gets the operation performed by this instruction in terms of its operands as a string.
-     */
-    public String operationString() {
-        StringBuilder buf = new StringBuilder();
-        String sep = "";
-        if (outputs.length > 1) {
-            buf.append("(");
-        }
-        for (Value output : outputs) {
-            buf.append(sep).append(output);
-            sep = ", ";
-        }
-        if (outputs.length > 1) {
-            buf.append(")");
-        }
-        if (outputs.length > 0) {
-            buf.append(" = ");
-        }
-
-        if (inputs.length + alives.length != 1) {
-            buf.append("(");
-        }
-        sep = "";
-        for (Value input : inputs) {
-            buf.append(sep).append(input);
-            sep = ", ";
-        }
-        for (Value input : alives) {
-            buf.append(sep).append(input).append(" ~");
-            sep = ", ";
-        }
-        if (inputs.length + alives.length != 1) {
-            buf.append(")");
-        }
-
-        if (temps.length > 0) {
-            buf.append(" [");
-        }
-        sep = "";
-        for (Value temp : temps) {
-            buf.append(sep).append(temp);
-            sep = ", ";
-        }
-        if (temps.length > 0) {
-            buf.append("]");
-        }
-        return buf.toString();
-    }
-
-    protected void appendDebugInfo(StringBuilder buf) {
-        if (info != null) {
-            buf.append(" [bci:");
-            String sep = "";
-            for (BytecodeFrame cur = info.topFrame; cur != null; cur = cur.caller()) {
-                buf.append(sep).append(cur.getBCI());
-                sep = ",";
-            }
-            buf.append("]");
-        }
-    }
-
     @Override
     public String toString() {
-        StringBuilder buf = new StringBuilder(name()).append(' ').append(operationString());
-        appendDebugInfo(buf);
-        return buf.toString();
+        return instructionClass.toString(this);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.StateProcedure;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+
+public class LIRInstructionClass {
+    // TODO(cwimmer) factor out the common methods of this class and NodeClass into a base class.
+
+    /**
+     * Interface used by {@link LIRInstructionClass#rescanAllFieldOffsets(CalcOffset)} to determine the offset (in bytes) of a field.
+     */
+    public interface CalcOffset {
+        long getOffset(Field field);
+    }
+
+    private static final Unsafe unsafe = getUnsafe();
+
+    private static Unsafe getUnsafe() {
+        try {
+            // this will only fail if graal is not part of the boot class path
+            return Unsafe.getUnsafe();
+        } catch (SecurityException e) {
+            // nothing to do
+        }
+        try {
+            Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafeInstance.setAccessible(true);
+            return (Unsafe) theUnsafeInstance.get(Unsafe.class);
+        } catch (Exception e) {
+            // currently we rely on being able to use Unsafe...
+            throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
+        }
+    }
+
+    static class DefaultCalcOffset implements CalcOffset {
+        @Override
+        public long getOffset(Field field) {
+            return unsafe.objectFieldOffset(field);
+        }
+    }
+
+    private static final Class<?> INSTRUCTION_CLASS = LIRInstruction.class;
+    private static final Class<?> VALUE_CLASS = Value.class;
+    private static final Class<?> VALUE_ARRAY_CLASS = Value[].class;
+    private static final Class<?> STATE_CLASS = LIRFrameState.class;
+
+
+    private static final ConcurrentHashMap<Class< ? >, LIRInstructionClass> classes = new ConcurrentHashMap<>();
+
+    private final Class< ? > clazz;
+    private final int directUseCount;
+    private final long[] useOffsets;
+    private final EnumSet<OperandFlag>[] useFlags;
+    private final int directAliveCount;
+    private final long[] aliveOffsets;
+    private final EnumSet<OperandFlag>[] aliveFlags;
+    private final int directTempCount;
+    private final long[] tempOffsets;
+    private final EnumSet<OperandFlag>[] tempFlags;
+    private final int directDefCount;
+    private final long[] defOffsets;
+    private final EnumSet<OperandFlag>[] defFlags;
+
+    private final long[] stateOffsets;
+    private final long[] dataOffsets;
+
+    private final Map<Long, String> fieldNames;
+    private final Map<Long, Class<?>> fieldTypes;
+
+    private String opcodeConstant;
+    private long opcodeOffset;
+
+    @SuppressWarnings("unchecked")
+    public LIRInstructionClass(Class<?> clazz) {
+        assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
+        this.clazz = clazz;
+
+        FieldScanner scanner = new FieldScanner(new DefaultCalcOffset());
+        scanner.scan(clazz);
+
+        OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
+        directUseCount = mode.scalarOffsets.size();
+        useOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
+        useFlags = arrayUsingSortedOffsets(mode.flags, useOffsets, new EnumSet[useOffsets.length]);
+
+        mode = scanner.valueAnnotations.get(LIRInstruction.Alive.class);
+        directAliveCount = mode.scalarOffsets.size();
+        aliveOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
+        aliveFlags = arrayUsingSortedOffsets(mode.flags, aliveOffsets, new EnumSet[aliveOffsets.length]);
+
+        mode = scanner.valueAnnotations.get(LIRInstruction.Temp.class);
+        directTempCount = mode.scalarOffsets.size();
+        tempOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
+        tempFlags = arrayUsingSortedOffsets(mode.flags, tempOffsets, new EnumSet[tempOffsets.length]);
+
+        mode = scanner.valueAnnotations.get(LIRInstruction.Def.class);
+        directDefCount = mode.scalarOffsets.size();
+        defOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
+        defFlags = arrayUsingSortedOffsets(mode.flags, defOffsets, new EnumSet[defOffsets.length]);
+
+        stateOffsets = sortedLongCopy(scanner.stateOffsets);
+        dataOffsets = sortedLongCopy(scanner.dataOffsets);
+
+        fieldNames = scanner.fieldNames;
+        fieldTypes = scanner.fieldTypes;
+
+        opcodeConstant = scanner.opcodeConstant;
+        opcodeOffset = scanner.opcodeOffset;
+    }
+
+    public static void rescanAllFieldOffsets(CalcOffset calc) {
+        for (LIRInstructionClass nodeClass : classes.values()) {
+            nodeClass.rescanFieldOffsets(calc);
+        }
+    }
+
+    private void rescanFieldOffsets(CalcOffset calc) {
+        FieldScanner scanner = new FieldScanner(calc);
+        scanner.scan(clazz);
+
+        OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
+        copyInto(useOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
+        mode = scanner.valueAnnotations.get(LIRInstruction.Alive.class);
+        copyInto(aliveOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
+        mode = scanner.valueAnnotations.get(LIRInstruction.Temp.class);
+        copyInto(tempOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
+        mode = scanner.valueAnnotations.get(LIRInstruction.Def.class);
+        copyInto(defOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
+
+        copyInto(stateOffsets, sortedLongCopy(scanner.stateOffsets));
+        copyInto(dataOffsets, sortedLongCopy(scanner.dataOffsets));
+
+        fieldNames.clear();
+        fieldNames.putAll(scanner.fieldNames);
+        fieldTypes.clear();
+        fieldTypes.putAll(scanner.fieldTypes);
+
+        opcodeConstant = scanner.opcodeConstant;
+        opcodeOffset = scanner.opcodeOffset;
+    }
+
+    private static void copyInto(long[] dest, long[] src) {
+        assert dest.length == src.length;
+        for (int i = 0; i < dest.length; i++) {
+            dest[i] = src[i];
+        }
+    }
+
+    public static final LIRInstructionClass get(Class<?> c) {
+        LIRInstructionClass clazz = classes.get(c);
+        if (clazz != null) {
+            return clazz;
+        }
+
+        // We can have a race of multiple threads creating the LIRInstructionClass at the same time.
+        // However, only one will be put into the map, and this is the one returned by all threads.
+        clazz = new LIRInstructionClass(c);
+        LIRInstructionClass oldClazz = classes.putIfAbsent(c, clazz);
+        if (oldClazz != null) {
+            return oldClazz;
+        } else {
+            return clazz;
+        }
+    }
+
+
+    private static class OperandModeAnnotation {
+        public final ArrayList<Long> scalarOffsets = new ArrayList<>();
+        public final ArrayList<Long> arrayOffsets = new ArrayList<>();
+        public final Map<Long, EnumSet<OperandFlag>> flags = new HashMap<>();
+    }
+
+    private static class FieldScanner {
+        public final CalcOffset calc;
+
+        public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations;
+        public final ArrayList<Long> stateOffsets = new ArrayList<>();
+        public final ArrayList<Long> dataOffsets = new ArrayList<>();
+
+        public final Map<Long, String> fieldNames = new HashMap<>();
+        public final Map<Long, Class<?>> fieldTypes = new HashMap<>();
+
+        private String opcodeConstant;
+        private long opcodeOffset;
+
+        public FieldScanner(CalcOffset calc) {
+            this.calc = calc;
+
+            valueAnnotations = new HashMap<>();
+            valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation()); //LIRInstruction.Use.class));
+            valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation()); //LIRInstruction.Alive.class));
+            valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation()); //LIRInstruction.Temp.class));
+            valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation()); //LIRInstruction.Def.class));
+        }
+
+        private OperandModeAnnotation getOperandModeAnnotation(Field field) {
+            OperandModeAnnotation result = null;
+            for (Entry<Class<? extends Annotation>, OperandModeAnnotation> entry  : valueAnnotations.entrySet()) {
+                Annotation annotation = field.getAnnotation(entry.getKey());
+                if (annotation != null) {
+                    assert result == null : "Field has two operand mode annotations: " + field;
+                    result = entry.getValue();
+                }
+            }
+            return result;
+        }
+
+        private static EnumSet<OperandFlag> getFlags(Field field) {
+            EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
+            // Unfortunately, annotations cannot have class hierarchies or implement interfaces, so we have to duplicate the code for every operand mode.
+            // Unfortunately, annotations cannot have an EnumSet property, so we have to convert from arrays to EnumSet manually.
+            if (field.isAnnotationPresent(LIRInstruction.Use.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Use.class).value()));
+            } else if (field.isAnnotationPresent(LIRInstruction.Alive.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Alive.class).value()));
+            } else if (field.isAnnotationPresent(LIRInstruction.Temp.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Temp.class).value()));
+            } else if (field.isAnnotationPresent(LIRInstruction.Def.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(LIRInstruction.Def.class).value()));
+            } else {
+                GraalInternalError.shouldNotReachHere();
+            }
+            return result;
+        }
+
+        public void scan(Class<?> clazz) {
+            if (clazz.getAnnotation(LIRInstruction.Opcode.class) != null) {
+                opcodeConstant = clazz.getAnnotation(LIRInstruction.Opcode.class).value();
+            }
+            opcodeOffset = -1;
+
+            Class<?> currentClazz = clazz;
+            do {
+                for (Field field : currentClazz.getDeclaredFields()) {
+                    if (Modifier.isStatic(field.getModifiers())) {
+                        continue;
+                    }
+
+                    Class< ? > type = field.getType();
+                    long offset = calc.getOffset(field);
+
+                    if (VALUE_CLASS.isAssignableFrom(type)) {
+                        assert Modifier.isProtected(field.getModifiers()) && !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final or private because it is modified by register allocator: " + field;
+                        OperandModeAnnotation annotation = getOperandModeAnnotation(field);
+                        assert annotation != null : "Field must have operand mode annotation: " + field;
+                        annotation.scalarOffsets.add(offset);
+                        annotation.flags.put(offset, getFlags(field));
+                    } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                        OperandModeAnnotation annotation = getOperandModeAnnotation(field);
+                        assert annotation != null : "Field must have operand mode annotation: " + field;
+                        annotation.arrayOffsets.add(offset);
+                        annotation.flags.put(offset, getFlags(field));
+                    } else if (STATE_CLASS.isAssignableFrom(type)) {
+                        assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
+                        assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field;
+                        stateOffsets.add(offset);
+                    } else {
+                        assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
+                        assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
+                        dataOffsets.add(offset);
+                    }
+                    fieldNames.put(offset, field.getName());
+                    fieldTypes.put(offset, type);
+
+                    if (field.getAnnotation(LIRInstruction.Opcode.class) != null) {
+                        assert opcodeConstant == null && opcodeOffset == -1 : "Can have only one Opcode definition: " + clazz;
+                        opcodeOffset = offset;
+                    }
+                }
+                currentClazz = currentClazz.getSuperclass();
+            } while (currentClazz != LIRInstruction.class);
+
+            if (opcodeConstant == null && opcodeOffset == -1) {
+                opcodeConstant = clazz.getSimpleName();
+                if (opcodeConstant.endsWith("Op")) {
+                    opcodeConstant = opcodeConstant.substring(0, opcodeConstant.length() - 2);
+                }
+            }
+        }
+    }
+
+    private static <T> T[] arrayUsingSortedOffsets(Map<Long, T> map, long[] sortedOffsets, T[] result) {
+        for (int i = 0; i < sortedOffsets.length; i++) {
+            result[i] = map.get(sortedOffsets[i]);
+        }
+        return result;
+    }
+
+    private static long[] sortedLongCopy(ArrayList<Long> list1) {
+        Collections.sort(list1);
+        long[] result = new long[list1.size()];
+        for (int i = 0; i < list1.size(); i++) {
+            result[i] = list1.get(i);
+        }
+        return result;
+    }
+
+    private static long[] sortedLongCopy(ArrayList<Long> list1, ArrayList<Long> list2) {
+        Collections.sort(list1);
+        Collections.sort(list2);
+        long[] result = new long[list1.size() + list2.size()];
+        for (int i = 0; i < list1.size(); i++) {
+            result[i] = list1.get(i);
+        }
+        for (int i = 0; i < list2.size(); i++) {
+            result[list1.size() + i] = list2.get(i);
+        }
+        return result;
+    }
+
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" use[");
+        for (int i = 0; i < useOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(useOffsets[i]);
+        }
+        str.append("] alive[");
+        for (int i = 0; i < aliveOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(aliveOffsets[i]);
+        }
+        str.append("] temp[");
+        for (int i = 0; i < tempOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(tempOffsets[i]);
+        }
+        str.append("] def[");
+        for (int i = 0; i < defOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(defOffsets[i]);
+        }
+        str.append("] state[");
+        for (int i = 0; i < stateOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(stateOffsets[i]);
+        }
+        str.append("] data[");
+        for (int i = 0; i < dataOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(dataOffsets[i]);
+        }
+        str.append("]");
+        return str.toString();
+    }
+
+
+    public final String getOpcode(LIRInstruction obj) {
+        if (opcodeConstant != null) {
+            return opcodeConstant;
+        }
+        assert opcodeOffset != -1;
+        return unsafe.getObject(obj, opcodeOffset).toString();
+    }
+
+    public final boolean hasOperands() {
+        return useOffsets.length > 0 || aliveOffsets.length > 0 || tempOffsets.length > 0 || defOffsets.length > 0;
+    }
+
+    public final boolean hasState(LIRInstruction obj) {
+        for (int i = 0; i < stateOffsets.length; i++) {
+            if (getState(obj, stateOffsets[i]) != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public final void forEachUse(LIRInstruction obj, ValueProcedure proc) {
+        forEach(obj, directUseCount, useOffsets, OperandMode.USE, useFlags, proc);
+    }
+
+    public final void forEachAlive(LIRInstruction obj, ValueProcedure proc) {
+        forEach(obj, directAliveCount, aliveOffsets, OperandMode.ALIVE, aliveFlags, proc);
+    }
+
+    public final void forEachTemp(LIRInstruction obj, ValueProcedure proc) {
+        forEach(obj, directTempCount, tempOffsets, OperandMode.TEMP, tempFlags, proc);
+    }
+
+    public final void forEachDef(LIRInstruction obj, ValueProcedure proc) {
+        forEach(obj, directDefCount, defOffsets, OperandMode.DEF, defFlags, proc);
+    }
+
+    public final void forEachState(LIRInstruction obj, ValueProcedure proc) {
+        for (int i = 0; i < stateOffsets.length; i++) {
+            LIRFrameState state = getState(obj, stateOffsets[i]);
+            if (state != null) {
+                state.forEachState(proc);
+            }
+        }
+    }
+
+    public final void forEachState(LIRInstruction obj, StateProcedure proc) {
+        for (int i = 0; i < stateOffsets.length; i++) {
+            LIRFrameState state = getState(obj, stateOffsets[i]);
+            if (state != null) {
+                proc.doState(state);
+            }
+        }
+    }
+
+    private static void forEach(LIRInstruction obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, ValueProcedure proc) {
+        for (int i = 0; i < offsets.length; i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+
+            if (i < directCount) {
+                Value value = getValue(obj, offsets[i]);
+                if (isAddress(value)) {
+                    doAddress(asAddress(value), mode, flags[i], proc);
+                } else {
+                    setValue(obj, offsets[i], proc.doValue(value, mode, flags[i]));
+                }
+            } else {
+                Value[] values = getValueArray(obj, offsets[i]);
+                for (int j = 0; j < values.length; j++) {
+                    Value value = values[j];
+                    if (isAddress(value)) {
+                        doAddress(asAddress(value), mode, flags[i], proc);
+                    } else {
+                        values[j] = proc.doValue(value, mode, flags[i]);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void doAddress(Address address, OperandMode mode, EnumSet<OperandFlag> flags, ValueProcedure proc) {
+        assert flags.contains(OperandFlag.ADDR);
+        address.setBase(proc.doValue(address.getBase(), mode, LIRInstruction.ADDRESS_FLAGS));
+        address.setIndex(proc.doValue(address.getIndex(), mode, LIRInstruction.ADDRESS_FLAGS));
+    }
+
+    public final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, ValueProcedure proc) {
+        int hintDirectCount = 0;
+        long[] hintOffsets = null;
+        if (mode == OperandMode.USE) {
+            hintDirectCount = directDefCount;
+            hintOffsets = defOffsets;
+        } else if (mode == OperandMode.DEF) {
+            hintDirectCount = directUseCount;
+            hintOffsets = useOffsets;
+        } else {
+            return null;
+        }
+
+        for (int i = 0; i < hintOffsets.length; i++) {
+            if (i < hintDirectCount) {
+                Value hintValue = getValue(obj, hintOffsets[i]);
+                Value result = proc.doValue(hintValue, null, null);
+                if (result != null) {
+                    return result;
+                }
+            } else {
+                Value[] hintValues = getValueArray(obj, hintOffsets[i]);
+                for (int j = 0; j < hintValues.length; j++) {
+                    Value hintValue = hintValues[j];
+                    Value result = proc.doValue(hintValue, null, null);
+                    if (result != null) {
+                        return result;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private static Value getValue(LIRInstruction obj, long offset) {
+        return (Value) unsafe.getObject(obj, offset);
+    }
+
+    private static void setValue(LIRInstruction obj, long offset, Value value) {
+        unsafe.putObject(obj, offset, value);
+    }
+
+    private static Value[] getValueArray(LIRInstruction obj, long offset) {
+        return (Value[]) unsafe.getObject(obj, offset);
+    }
+
+    private static LIRFrameState getState(LIRInstruction obj, long offset) {
+        return (LIRFrameState) unsafe.getObject(obj, offset);
+    }
+
+
+    public String toString(LIRInstruction obj) {
+        StringBuilder result = new StringBuilder();
+
+        appendValues(result, obj, "", " = ", "(", ")", new String[] {""}, defOffsets);
+        result.append(getOpcode(obj).toUpperCase());
+        appendValues(result, obj, " ", "", "(", ")", new String[] {"", "~"}, useOffsets, aliveOffsets);
+        appendValues(result, obj, " ", "", "{", "}", new String[] {""}, tempOffsets);
+
+        for (int i = 0; i < dataOffsets.length; i++) {
+            if (dataOffsets[i] == opcodeOffset) {
+                continue;
+            }
+            result.append(" ").append(fieldNames.get(dataOffsets[i])).append(": ").append(getFieldString(obj, dataOffsets[i]));
+        }
+
+        for (int i = 0; i < stateOffsets.length; i++) {
+            LIRFrameState state = getState(obj, stateOffsets[i]);
+            if (state != null) {
+                result.append(" ").append(fieldNames.get(stateOffsets[i])).append(" [bci:");
+                String sep = "";
+                for (BytecodeFrame cur = state.topFrame; cur != null; cur = cur.caller()) {
+                    result.append(sep).append(cur.getBCI());
+                    sep = ", ";
+                }
+                result.append("]");
+            }
+        }
+
+        return result.toString();
+    }
+
+    private void appendValues(StringBuilder result, LIRInstruction obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, long[]...moffsets) {
+        int total = 0;
+        for (long[] offsets : moffsets) {
+            total += offsets.length;
+        }
+        if (total == 0) {
+            return;
+        }
+
+        result.append(start);
+        if (total > 1) {
+            result.append(startMultiple);
+        }
+        String sep = "";
+        for (int i = 0; i < moffsets.length; i++) {
+            long[] offsets = moffsets[i];
+
+            for (int j = 0; j < offsets.length; j++) {
+                result.append(sep).append(prefix[i]);
+                long offset = offsets[j];
+                if (total > 1) {
+                    result.append(fieldNames.get(offset)).append(": ");
+                }
+                result.append(getFieldString(obj, offset));
+                sep = ", ";
+            }
+        }
+        if (total > 1) {
+            result.append(endMultiple);
+        }
+        result.append(end);
+    }
+
+    private String getFieldString(Object obj, long offset) {
+        Class<?> type = fieldTypes.get(offset);
+        if (type == int.class) {
+            return String.valueOf(unsafe.getInt(obj, offset));
+        } else if (type == long.class) {
+            return String.valueOf(unsafe.getLong(obj, offset));
+        } else if (type == boolean.class) {
+            return String.valueOf(unsafe.getBoolean(obj, offset));
+        } else if (type == float.class) {
+            return String.valueOf(unsafe.getFloat(obj, offset));
+        } else if (type == double.class) {
+            return String.valueOf(unsafe.getDouble(obj, offset));
+        } else if (!type.isPrimitive()) {
+            Object value = unsafe.getObject(obj, offset);
+            if (!type.isArray()) {
+                return String.valueOf(value);
+            } else if (type == int[].class) {
+                return Arrays.toString((int[]) value);
+            } else if (type == double[].class) {
+                return Arrays.toString((double[]) value);
+            } else if (!type.getComponentType().isPrimitive()) {
+                return Arrays.toString((Object[]) value);
+            }
+        }
+        assert false : "unhandled field type: " + type;
+        return "";
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Mon Jul 02 18:20:25 2012 +0200
@@ -171,7 +171,7 @@
 
         } else if (isAllocatableRegister(value)) {
             int regNum = asRegister(value).number;
-            if (mode == OperandMode.Alive) {
+            if (mode == OperandMode.ALIVE) {
                 curRegistersDefined.set(regNum);
             }
 
@@ -202,7 +202,7 @@
             assert curInstruction != null;
             variableDefinitions[variableIdx] = curInstruction;
             assert !curVariablesLive.get(variableIdx);
-            if (mode == OperandMode.Output) {
+            if (mode == OperandMode.DEF) {
                 curVariablesLive.set(variableIdx);
             }
 
@@ -216,7 +216,7 @@
             curRegistersDefined.set(regNum);
 
             if (beforeRegisterAllocation) {
-                if (mode == OperandMode.Output) {
+                if (mode == OperandMode.DEF) {
                     curRegistersLive[regNum] = value;
                 } else {
                     curRegistersLive[regNum] = null;
@@ -227,11 +227,11 @@
     }
 
     private static Value allowed(Object op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        if ((isVariable(value)  && flags.contains(OperandFlag.Register)) ||
-            (isRegister(value)  && flags.contains(OperandFlag.Register)) ||
-            (isStackSlot(value) && flags.contains(OperandFlag.Stack)) ||
-            (isConstant(value)  && flags.contains(OperandFlag.Constant) && mode != OperandMode.Output) ||
-            (isIllegal(value)   && flags.contains(OperandFlag.Illegal))) {
+        if ((isVariable(value)  && flags.contains(OperandFlag.REG)) ||
+            (isRegister(value)  && flags.contains(OperandFlag.REG)) ||
+            (isStackSlot(value) && flags.contains(OperandFlag.STACK)) ||
+            (isConstant(value)  && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) ||
+            (isIllegal(value)   && flags.contains(OperandFlag.ILLEGAL))) {
             return value;
         }
         TTY.println("instruction %s", op);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRXirInstruction.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRXirInstruction.java	Mon Jul 02 18:20:25 2012 +0200
@@ -23,39 +23,47 @@
 package com.oracle.graal.lir;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
-
-import java.util.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.max.cri.xir.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 
 public abstract class LIRXirInstruction extends LIRInstruction {
+    @Opcode protected final String opcode;
+    @Def({REG, ILLEGAL}) protected Value outputOperand;
+    @Alive({REG, CONST, ILLEGAL}) protected Value[] inputs;
+    @Temp({REG, CONST, ILLEGAL}) protected Value[] temps;
+    @State protected LIRFrameState state;
+    @State protected LIRFrameState stateAfter;
 
-    public final Value[] originalOperands;
+    // Defined as Object[] so that the magic processing of Value[] does not complain this field is not annotated.
+    public final Object[] originalOperands;
+
     public final int outputOperandIndex;
     public final int[] inputOperandIndices;
     public final int[] tempOperandIndices;
     public final XirSnippet snippet;
-    public final LIRDebugInfo infoAfter;
     public final LabelRef trueSuccessor;
     public final LabelRef falseSuccessor;
 
-    public LIRXirInstruction(Object opcode,
-                             XirSnippet snippet,
+    public LIRXirInstruction(XirSnippet snippet,
                              Value[] originalOperands,
                              Value outputOperand,
                              Value[] inputs, Value[] temps,
                              int[] inputOperandIndices, int[] tempOperandIndices,
                              int outputOperandIndex,
-                             LIRDebugInfo info,
-                             LIRDebugInfo infoAfter,
+                             LIRFrameState state,
+                             LIRFrameState stateAfter,
                              LabelRef trueSuccessor,
                              LabelRef falseSuccessor) {
         // Note that we register the XIR input operands as Alive, because the XIR specification allows that input operands
         // are used at any time, even when the temp operands and the actual output operands have already be assigned.
-        super(opcode, isLegal(outputOperand) ? new Value[] {outputOperand} : LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, inputs, temps);
-        this.infoAfter = infoAfter;
+        this.opcode = "XIR: " + snippet.template;
+        this.outputOperand = outputOperand;
+        this.inputs = inputs;
+        this.temps = temps;
+        this.state = state;
+        this.stateAfter = stateAfter;
         this.snippet = snippet;
         this.inputOperandIndices = inputOperandIndices;
         this.tempOperandIndices = tempOperandIndices;
@@ -66,31 +74,16 @@
         assert isLegal(outputOperand) || outputOperandIndex == -1;
     }
 
-    @Override
-    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-        if (mode == OperandMode.Alive || mode == OperandMode.Temp) {
-            return EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.Illegal);
-        } else if (mode == OperandMode.Output && index == 0) {
-            return EnumSet.of(OperandFlag.Register);
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
-
     public Value[] getOperands() {
         for (int i = 0; i < inputOperandIndices.length; i++) {
-            originalOperands[inputOperandIndices[i]] = alive(i);
+            originalOperands[inputOperandIndices[i]] = inputs[i];
         }
         for (int i = 0; i < tempOperandIndices.length; i++) {
-            originalOperands[tempOperandIndices[i]] = temp(i);
+            originalOperands[tempOperandIndices[i]] = temps[i];
         }
         if (outputOperandIndex != -1) {
-            originalOperands[outputOperandIndex] = output(0);
+            originalOperands[outputOperandIndex] = outputOperand;
         }
-        return originalOperands;
-    }
-
-    @Override
-    public String name() {
-        return "XIR: " + snippet.template;
+        return (Value[]) originalOperands;
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Mon Jul 02 18:20:25 2012 +0200
@@ -22,12 +22,10 @@
  */
 package com.oracle.graal.lir;
 
-import java.util.*;
-
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.max.asm.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.asm.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 /**
  * A collection of machine-independent LIR operations, as well as interfaces to be implemented for specific kinds or LIR
@@ -54,16 +52,11 @@
         private final Label label;
         private final boolean align;
 
-        protected LabelOp(Object opcode, Value[] outputs, LIRDebugInfo info, Value[] inputs, Value[] alives, Value[] temps, Label label, boolean align) {
-            super(opcode, outputs, info, inputs, alives, temps);
+        public LabelOp(Label label, boolean align) {
             this.label = label;
             this.align = align;
         }
 
-        public LabelOp(Label label, boolean align) {
-            this("LABEL", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, label, align);
-        }
-
         @Override
         public void emitCode(TargetMethodAssembler tasm) {
             if (align) {
@@ -72,40 +65,25 @@
             tasm.asm.bind(label);
         }
 
-        @Override
-        public String operationString() {
-            return label.toString() + " " + super.operationString();
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
         public Label getLabel() {
             return label;
         }
     }
 
     public static class PhiLabelOp extends LabelOp {
-        public PhiLabelOp(Label label, boolean align, Value[] phiDefinitions) {
-            super("PHI_LABEL", phiDefinitions, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, label, align);
-        }
+        @Def({REG, STACK}) protected Value[] phiDefinitions;
 
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Output) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+        public PhiLabelOp(Label label, boolean align, Value[] phiDefinitions) {
+            super(label, align);
+            this.phiDefinitions = phiDefinitions;
         }
 
         public void markResolved() {
-            outputs = EMPTY;
+            phiDefinitions = EMPTY;
         }
 
         public Value[] getPhiDefinitions() {
-            return outputs;
+            return phiDefinitions;
         }
     }
 
@@ -118,14 +96,11 @@
      */
     public static class JumpOp extends LIRInstruction {
         private final LabelRef destination;
+        @State protected LIRFrameState state;
 
-        protected JumpOp(Object opcode, Value[] outputs, LIRDebugInfo info, Value[] inputs, Value[] alives, Value[] temps, LabelRef destination) {
-            super(opcode, outputs, info, inputs, alives, temps);
+        public JumpOp(LabelRef destination, LIRFrameState state) {
             this.destination = destination;
-        }
-
-        public JumpOp(LabelRef destination, LIRDebugInfo info) {
-            this("JUMP", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, destination);
+            this.state = state;
         }
 
         @Override
@@ -133,40 +108,25 @@
             tasm.asm.jmp(destination.label());
         }
 
-        @Override
-        public String operationString() {
-            return  destination + " " + super.operationString();
-        }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-
         public LabelRef destination() {
             return destination;
         }
     }
 
     public static class PhiJumpOp extends JumpOp {
-        public PhiJumpOp(LabelRef destination, Value[] phiInputs) {
-            super("PHI_JUMP", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, phiInputs, LIRInstruction.NO_OPERANDS, destination);
-        }
+        @Alive({REG, STACK, CONST}) protected Value[] phiInputs;
 
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Alive) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
-            }
-            throw GraalInternalError.shouldNotReachHere();
+        public PhiJumpOp(LabelRef destination, Value[] phiInputs) {
+            super(destination, null);
+            this.phiInputs = phiInputs;
         }
 
         public void markResolved() {
-            alives = EMPTY;
+            phiInputs = EMPTY;
         }
 
         public Value[] getPhiInputs() {
-            return alives;
+            return phiInputs;
         }
     }
 
@@ -200,21 +160,15 @@
      * In particular, it is not the actual method prologue.
      */
     public static final class ParametersOp extends LIRInstruction {
+        @Def({REG, STACK}) protected Value[] params;
+
         public ParametersOp(Value[] params) {
-            super("PARAMS", params, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            this.params = params;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm) {
             // No code to emit.
         }
-
-        @Override
-        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-            if (mode == OperandMode.Output) {
-                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
-            }
-            throw GraalInternalError.shouldNotReachHere();
-        }
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Mon Jul 02 18:20:25 2012 +0200
@@ -159,7 +159,7 @@
         return targetMethod;
     }
 
-    public void recordExceptionHandlers(int pcOffset, LIRDebugInfo info) {
+    public void recordExceptionHandlers(int pcOffset, LIRFrameState info) {
         if (info != null) {
             if (info.exceptionEdge != null) {
                 if (exceptionInfoList == null) {
@@ -170,7 +170,7 @@
         }
     }
 
-    public void recordImplicitException(int pcOffset, LIRDebugInfo info) {
+    public void recordImplicitException(int pcOffset, LIRFrameState info) {
         // record an implicit exception point
         if (info != null) {
             assert lastSafepointPos < pcOffset : lastSafepointPos + "<" + pcOffset;
@@ -180,21 +180,21 @@
         }
     }
 
-    public void recordDirectCall(int posBefore, int posAfter, Object callTarget, LIRDebugInfo info) {
+    public void recordDirectCall(int posBefore, int posAfter, Object callTarget, LIRFrameState info) {
         DebugInfo debugInfo = info != null ? info.debugInfo() : null;
         assert lastSafepointPos < posAfter;
         lastSafepointPos = posAfter;
         targetMethod.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, true);
     }
 
-    public void recordIndirectCall(int posBefore, int posAfter, Object callTarget, LIRDebugInfo info) {
+    public void recordIndirectCall(int posBefore, int posAfter, Object callTarget, LIRFrameState info) {
         DebugInfo debugInfo = info != null ? info.debugInfo() : null;
         assert lastSafepointPos < posAfter;
         lastSafepointPos = posAfter;
         targetMethod.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, false);
     }
 
-    public void recordSafepoint(int pos, LIRDebugInfo info) {
+    public void recordSafepoint(int pos, LIRFrameState info) {
         // safepoints always need debug info
         DebugInfo debugInfo = info.debugInfo();
         assert lastSafepointPos < pos;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Mon Jul 02 18:20:25 2012 +0200
@@ -432,18 +432,21 @@
             LIRInstruction inst = lirInstructions.get(i);
             out.printf("nr %4d ", inst.id()).print(COLUMN_END);
 
-            if (inst.info != null) {
+            final StringBuilder stateString = new StringBuilder();
+            inst.forEachState(new LIRInstruction.StateProcedure() {
+                @Override
+                protected void doState(LIRFrameState state) {
+                    if (state.hasDebugInfo()) {
+                        stateString.append(debugInfoToString(state.debugInfo().getBytecodePosition(), state.debugInfo().getRegisterRefMap(), state.debugInfo().getFrameRefMap(), target.arch));
+                    } else {
+                        stateString.append(debugInfoToString(state.topFrame, null, null, target.arch));
+                    }
+                }
+            });
+            if (stateString.length() > 0) {
                 int level = out.indentationLevel();
                 out.adjustIndentation(-level);
-                String state;
-                if (inst.info.hasDebugInfo()) {
-                    state = debugInfoToString(inst.info.debugInfo().getBytecodePosition(), inst.info.debugInfo().getRegisterRefMap(), inst.info.debugInfo().getFrameRefMap(), target.arch);
-                } else {
-                    state = debugInfoToString(inst.info.topFrame, null, null, target.arch);
-                }
-                if (state != null) {
-                    out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).print(COLUMN_END);
-                }
+                out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(stateString.toString()).print(HOVER_END).print(COLUMN_END);
                 out.adjustIndentation(level);
             }
 
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MathIntrinsicNode.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/MathIntrinsicNode.java	Mon Jul 02 18:20:25 2012 +0200
@@ -66,12 +66,12 @@
         Variable result = gen.newVariable(kind());
         switch (operation()) {
             case ABS:   gen.append(new Op2Reg(DAND, result, input, Constant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)))); break;
-            case SQRT:  gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.Opcode.SQRT, result, input)); break;
-            case LOG:   gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.Opcode.LOG, result, input)); break;
-            case LOG10: gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.Opcode.LOG10, result, input)); break;
-            case SIN:   gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.Opcode.SIN, result, input)); break;
-            case COS:   gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.Opcode.COS, result, input)); break;
-            case TAN:   gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.Opcode.TAN, result, input)); break;
+            case SQRT:  gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.IntrinsicOpcode.SQRT, result, input)); break;
+            case LOG:   gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.IntrinsicOpcode.LOG, result, input)); break;
+            case LOG10: gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.IntrinsicOpcode.LOG10, result, input)); break;
+            case SIN:   gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.IntrinsicOpcode.SIN, result, input)); break;
+            case COS:   gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.IntrinsicOpcode.COS, result, input)); break;
+            case TAN:   gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.IntrinsicOpcode.TAN, result, input)); break;
             default:    throw GraalInternalError.shouldNotReachHere();
         }
         gen.setResult(this, result);
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/target/amd64/AMD64MathIntrinsicOp.java	Mon Jul 02 16:53:12 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/target/amd64/AMD64MathIntrinsicOp.java	Mon Jul 02 18:20:25 2012 +0200
@@ -24,32 +24,31 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 
-import java.util.*;
-
-import com.oracle.max.asm.target.amd64.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
 
 public class AMD64MathIntrinsicOp extends AMD64LIRInstruction {
-    public enum Opcode  {
+    public enum IntrinsicOpcode  {
         SQRT,
         SIN, COS, TAN,
         LOG, LOG10;
     }
 
-    public AMD64MathIntrinsicOp(Opcode opcode, Value result, Value input) {
-        super(opcode, new Value[] {result}, null, new Value[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+    @Opcode private final IntrinsicOpcode opcode;
+    @Def protected Value result;
+    @Use protected Value input;
+
+    public AMD64MathIntrinsicOp(IntrinsicOpcode opcode, Value result, Value input) {
+        this.opcode = opcode;
+        this.result = result;
+        this.input = input;
     }
 
     @Override
     public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        Opcode opcode = (Opcode) code;
-        Value result = output(0);
-        Value input = input(0);
-
         switch (opcode) {
             case SQRT:  masm.sqrtsd(asDoubleReg(result), asDoubleReg(input)); break;
             case LOG:   masm.flog(asDoubleReg(result), asDoubleReg(input), false); break;
@@ -60,14 +59,4 @@
             default:    throw GraalInternalError.shouldNotReachHere();
         }
     }
-
-    @Override
-    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
-        if (mode == OperandMode.Input && index == 0) {
-            return EnumSet.of(OperandFlag.Register);
-        } else if (mode == OperandMode.Output && index == 0) {
-            return EnumSet.of(OperandFlag.Register);
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/build.xml	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
+<!-- for some information on what you could do (e.g. targets to override). -->
+<!-- If you delete this file and reopen the project it will be recreated. -->
+<project name="com.oracle.graal.visualizer.logviewer" default="netbeans" basedir=".">
+    <description>Builds, tests, and runs the project com.oracle.graal.visualizer.logviewer.</description>
+    <import file="nbproject/build-impl.xml"/>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/manifest.mf	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+OpenIDE-Module: com.oracle.graal.visualizer.logviewer
+OpenIDE-Module-Layer: com/oracle/graal/visualizer/logviewer/layer.xml
+OpenIDE-Module-Localizing-Bundle: com/oracle/graal/visualizer/logviewer/Bundle.properties
+OpenIDE-Module-Specification-Version: 1.0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/nbproject/build-impl.xml	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+-->
+<project name="com.oracle.graal.visualizer.logviewer-impl" basedir="..">
+    <fail message="Please build using Ant 1.7.1 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.7.1"/>
+            </not>
+        </condition>
+    </fail>
+    <property file="nbproject/private/suite-private.properties"/>
+    <property file="nbproject/suite.properties"/>
+    <fail unless="suite.dir">You must set 'suite.dir' to point to your containing module suite</fail>
+    <property file="${suite.dir}/nbproject/private/platform-private.properties"/>
+    <property file="${suite.dir}/nbproject/platform.properties"/>
+    <macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-project/2">
+        <attribute name="name"/>
+        <attribute name="value"/>
+        <sequential>
+            <property name="@{name}" value="${@{value}}"/>
+        </sequential>
+    </macrodef>
+    <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-project/2">
+        <attribute name="property"/>
+        <attribute name="value"/>
+        <sequential>
+            <property name="@{property}" value="@{value}"/>
+        </sequential>
+    </macrodef>
+    <property file="${user.properties.file}"/>
+    <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <nbmproject2:property name="nbplatform.active.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <nbmproject2:evalprops property="cluster.path.evaluated" value="${cluster.path}" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness).">
+        <condition>
+            <not>
+                <contains string="${cluster.path.evaluated}" substring="platform"/>
+            </not>
+        </condition>
+    </fail>
+    <import file="${harness.dir}/build.xml"/>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/nbproject/genfiles.properties	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=979ec129
+build.xml.script.CRC32=1c914106
+build.xml.stylesheet.CRC32=a56c6a5b@2.47.2
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=979ec129
+nbproject/build-impl.xml.script.CRC32=712ab216
+nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.47.2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/nbproject/project.properties	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,2 @@
+javac.source=1.7
+javac.compilerargs=-Xlint -Xlint:-serial
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/nbproject/project.xml	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.apisupport.project</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
+            <code-name-base>com.oracle.graal.visualizer.logviewer</code-name-base>
+            <suite-component/>
+            <module-dependencies>
+                <dependency>
+                    <code-name-base>com.oracle.graal.visualizer.editor</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>com.oracle.graal.visualizer.sharedactions</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>com.sun.hotspot.igv.data</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.eclipse.draw2d</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.jdesktop.layout</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.19.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.api.visual</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>2.30.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.options.api</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.24.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.projectapi</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.40.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.actions</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>6.24.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.awt</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.39.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.dialogs</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.23.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.loaders</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.32.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.nodes</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.25.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>8.19.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util.lookup</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>8.11.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.windows</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>6.39.1</specification-version>
+                    </run-dependency>
+                </dependency>
+            </module-dependencies>
+            <public-packages>
+                <package>com.oracle.graal.visualizer.logviewer</package>
+            </public-packages>
+        </data>
+    </configuration>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/nbproject/suite.properties	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,1 @@
+suite.dir=${basedir}/..
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/META-INF/services/com.oracle.graal.visualizer.editor.CompilationViewerFactory	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,1 @@
+com.oracle.graal.visualizer.logviewer.LogCompilationViewerFactory
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/Bundle.properties	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,1 @@
+OpenIDE-Module-Name=LogViewer
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/LogCompilationViewer.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer;
+
+import com.oracle.graal.visualizer.logviewer.scene.LogScene;
+import com.oracle.graal.visualizer.editor.CompilationViewer;
+import com.sun.hotspot.igv.data.InputGraph;
+import java.awt.Component;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+class LogCompilationViewer implements CompilationViewer {
+
+    private LogScene scene;
+
+    public LogCompilationViewer() {
+        this.scene = new LogScene();
+    }
+
+    @Override
+    public Lookup getLookup() {
+        return Lookups.fixed();
+    }
+
+    @Override
+    public Component getComponent() {
+        return scene;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/LogCompilationViewerFactory.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer;
+
+import com.oracle.graal.visualizer.editor.CompilationViewer;
+import com.oracle.graal.visualizer.editor.SplitCompilationViewerFactory;
+import com.sun.hotspot.igv.data.InputGraph;
+
+public class LogCompilationViewerFactory extends SplitCompilationViewerFactory {
+
+    @Override
+    public String getName() {
+        return "Log";
+    }
+
+    @Override
+    protected CompilationViewer createViewer(InputGraph graph) {
+        return new LogCompilationViewer();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/layer.xml	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
+<filesystem>
+    <folder name="CompilationViewer">
+        <folder name="Log">
+            <folder name="Actions">
+                <file name="com-oracle-graal-visualizer-logviewer-scene-actions-ImportLogAction.shadow">
+                    <attr name="originalFile" stringvalue="Actions/File/com-oracle-graal-visualizer-logviewer-scene-actions-ImportLogActions.instance"/>
+                </file>
+            </folder>
+        </folder>
+    </folder>
+</filesystem>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/LogLine.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+public class LogLine {
+
+    private final int lineNum;
+	private final CharSequence text;
+	private final Method method;
+	private final Scope scope;
+	private final Node node;
+	
+	LogLine(int lineNum, CharSequence text, Method method, Scope scope, Node node) {
+		this.lineNum = lineNum;
+        this.text = text;
+		this.method = method;
+		this.scope = scope;
+		this.node = node;
+	}
+    
+    /**
+     * Returns the number of the line in the log file
+     * @return file line number
+     */
+    public int getLineNumber() {
+        return lineNum;
+    }
+	
+	/**
+	 * Returns the text of the log line
+	 * @return log line text
+	 */
+	public String getText() {
+		return text.toString();
+	}
+	
+	/**
+	 * Returns the parent method
+	 * @return the parent method
+	 */
+	public Method getMethod() {
+		return method;
+	}
+	
+	/**
+	 * Returns the parent scope
+	 * @return the parent scope
+	 */
+	public Scope getScope() {
+		return scope;
+	}
+	
+	/**
+	 * Returns the parent node
+	 * @return the parent node (or <code>null</code> if the log is not in a node's context)
+	 */
+	public Node getNode() {
+		return node;
+	}
+	
+	/**
+	 * The string representation of a log line is the text of it.
+	 */
+	@Override
+	public String toString() {
+		return getText();
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/LogModel.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+public class LogModel {
+
+	private List<Method> methods = new ArrayList<>();
+	private List<LogLine> logs = new ArrayList<>();
+	
+	void add(Method method) {
+		methods.add(method);
+	}
+	
+	/**
+	 * Returns a list of all methods within the log model.
+	 * @return list of methods
+	 */
+	public List<Method> getMethods() {
+		return Collections.unmodifiableList(methods);
+	}
+	
+	void add(LogLine log) {
+		logs.add(log);
+	}
+	
+	/**
+	 * Returns a list of all logs
+	 * @return list of log lines
+	 */
+	public List<LogLine> getLogs() {
+		return Collections.unmodifiableList(logs);
+	}
+	
+	/**
+	 * Returns a list of logs which are before and after a specific log line (and the line itself).
+	 * @param log reference log line
+	 * @param pre number of lines before the reference line
+	 * @param post number of lines after the reference line
+	 * @return list of log lines (size: pre + post + 1)
+	 */
+	public List<LogLine> range(LogLine log, int pre, int post) {
+		if(log == null) throw new NoSuchElementException();
+		
+		List<LogLine> logs = getLogs();
+		int index = logs.indexOf(log);
+		
+		if(index == -1) throw new NoSuchElementException();
+		
+		int fromIndex = index - pre;
+		int toIndex = index + post + 1;
+		
+		return getLogs().subList(fromIndex > 0 ? fromIndex : 0, toIndex < logs.size() ? toIndex : logs.size());
+	}
+	
+	/**
+	 * Returns a string with log l which are before and after a specific log line (and the line itself).
+	 * @param log reference log line
+	 * @param pre number of lines before the reference line
+	 * @param post number of lines after the reference line
+	 * @return list of log lines (size: pre + post + 1)
+	 */
+	public String rangeAsString(LogLine log, int pre, int post) {
+		List<LogLine> list = range(log, pre, post);
+		
+		String ls = System.getProperty("line.separator");
+		
+		boolean first = true;
+		StringBuilder buf = new StringBuilder();
+		for(LogLine line : list) {
+			if(!first) buf.append(ls);
+			else first = false;
+			
+			buf.append(line);
+		}
+		
+		return buf.toString();
+	}
+	
+	public LogLine getLogLine(int lineNum) {
+		int index = lineNum;
+		if(index >= logs.size()) index = logs.size()-1;
+		
+		LogLine logLine = logs.get(lineNum);
+		while(logLine.getLineNumber() > lineNum) {
+			logLine = logs.get(--index);
+		}
+		while(logLine.getLineNumber() < lineNum) {
+			logLine = logs.get(++index);
+		}
+		
+		return logLine;
+	}
+	
+	public List<LogLine> range(int lineNum, int pre, int post) {
+		LogLine logLine = getLogLine(lineNum);
+		return range(logLine, pre, post);
+	}
+	
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/LogParser.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import com.oracle.graal.visualizer.logviewer.model.io.FileLine;
+import com.oracle.graal.visualizer.logviewer.model.io.ProgressMonitor;
+import com.oracle.graal.visualizer.logviewer.model.io.SeekableFile;
+import com.oracle.graal.visualizer.logviewer.model.io.SeekableFileReader;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LogParser {
+	
+	private static final Pattern METHOD_PATTERN =
+		Pattern.compile("Finished target method HotSpotMethod<(.+?)>, isStub (true|false)");
+	private static final Pattern SCOPE_PATTERN =
+		Pattern.compile("scope: (.+?)");
+	private static final Pattern NODE_PATTERN =
+		Pattern.compile(".*?([0-9]+)\\|([0-9a-zA-Z.]+).*?");
+	
+	private final List<ParseErrorListener> errorListeners = new ArrayList<>();
+	private final List<ParseError> errors = new ArrayList<>();
+	
+	/**
+	 * Parses a log file without any feedback. When the parsing process is finished, the method returns a LogModel-object.
+	 * @param file log file
+	 * @return model-object
+	 * @throws IOException
+	 * @throws LogParserException
+	 */
+	public LogModel parse(File file) throws IOException {
+		return parse(file, null);
+	}
+	
+	/**
+	 * Parses a log file and uses a ProgressMonitor to give the caller a progress feedback. It returns a LogModel-object.
+	 * @param file log file
+	 * @param monitor monitor for progress monitoring (uses default gap)
+	 * @return model-object
+	 * @throws IOException
+	 * @throws LogParserException
+	 */
+	public LogModel parse(File file, ProgressMonitor monitor) throws IOException {
+		return parse(file, monitor, SeekableFileReader.DEFAULT_GAP);
+	} 
+	
+	/**
+	 * Parses a log file and uses a ProgressMonitor to give the caller a progress feedback. It returns a LogModel-object.
+	 * @param file log file
+	 * @param monitor monitor for progress monitoring (uses custom gap)
+	 * @param gap custom gap (every x bytes read from the file, the monitor will be informed)
+	 * @return model-object
+	 * @throws IOException
+	 * @throws LogParserException
+	 */
+	public LogModel parse(File file, ProgressMonitor monitor, int gap) throws IOException {
+		errors.clear();
+		SeekableFileReader reader = new SeekableFileReader(file, monitor, gap);
+		SeekableFile seekableFile = reader.getSeekableFile();
+		BufferedReader r = new BufferedReader(reader);
+		
+		LogModel model = new LogModel();
+		Method currentMethod = new Method(model);
+		Scope currentScope = null;
+		
+		Matcher matcher;
+		boolean methodNameSet = false;
+		
+		int lineNum = -1;
+		String line;
+		while((line = r.readLine()) != null) {
+			lineNum++;
+			
+			methodNameSet = false;
+			
+			matcher = SCOPE_PATTERN.matcher(line);
+			if(matcher.matches()) {
+				String name = matcher.group(1);
+				currentScope = new Scope(name, currentMethod);
+				currentMethod.add(currentScope);
+			}
+            
+            matcher = METHOD_PATTERN.matcher(line);
+            boolean methodPatternMatches = matcher.matches();
+            
+            if(methodPatternMatches){
+                currentScope = null;
+				String name = matcher.group(1);
+				boolean isStub = Boolean.parseBoolean(matcher.group(2));
+				currentMethod.init(name, isStub);
+				model.add(currentMethod);
+				methodNameSet = true;
+            }
+			
+			Node currentNode = null;
+			matcher = NODE_PATTERN.matcher(line);
+			if(matcher.matches()) {
+                if(currentScope == null){
+                	raiseError(lineNum, line, "scope is missing");
+                	continue;
+                }
+				int number = Integer.parseInt(matcher.group(1));
+				currentNode = currentScope.getNode(number);
+				if(currentNode == null) {
+					String name = matcher.group(2);
+					currentNode = new Node(number, name, currentScope);
+					currentScope.add(currentNode);
+				}
+			}
+			
+			FileLine fileLine = seekableFile.get(lineNum);
+			LogLine log = new LogLine(lineNum, fileLine, currentMethod, currentScope, currentNode);
+			if(currentNode != null) currentNode.add(log);
+			if(currentScope != null) currentScope.add(log);
+			currentMethod.add(log);
+			model.add(log);
+            
+            if(methodPatternMatches) {
+				currentMethod = new Method(model);
+			}
+		}
+		
+		if(!methodNameSet) raiseError(lineNum, line, "unexpected end of stream");
+		
+		return model;
+	}
+	
+	private void raiseError(int lineNum, String line, String message) {
+		ParseError error = new ParseError(lineNum, line, message);
+		errors.add(error);
+		for(ParseErrorListener listener : errorListeners) {
+			listener.errorOccurred(error);
+		}
+	}
+	
+	/**
+	 * Adds a ParseErrorListener to the listeners
+	 * @param listener
+	 */
+	public void addParseErrorListener(ParseErrorListener listener) {
+		errorListeners.add(listener);
+	}
+	
+	public void removeParseErrorListener(ParseErrorListener listener) {
+		errorListeners.remove(listener);
+	}
+	
+	/**
+	 * Checks if errors occurred during the parsing process
+	 * @return <code>true</code> if there are errors stored, <code>false</code> otherwise
+	 */
+	public boolean hasErrors() {
+		return !errors.isEmpty();
+	}
+	
+	/**
+	 * Returns a list of all errors.
+	 * @return error list
+	 */
+	public List<ParseError> getErrors() {
+		return Collections.unmodifiableList(errors);
+	}
+	
+	public static class ParseError {
+		
+		private final int lineNum;
+		private final String line;
+		private final String message;
+		
+		private ParseError(int lineNum, String line, String message) {
+			this.lineNum = lineNum;
+			this.message = message;
+			this.line = line;
+		}
+		
+		public int getLineNumber() {
+			return lineNum;
+		}
+		
+		public String getLine() {
+			return line;
+		}
+		
+		public String getMessage() {
+			return message;
+		}
+		
+	}
+	
+	public static interface ParseErrorListener {
+		
+		/**
+		 * Called when a new error occurs.<br><br>
+		 * <b>Attention</b>: This method runs on the same thread as the parsing process.
+		 * If time-consuming tasks should be executed, please consider multithreading.
+		 * @param error
+		 */
+		public void errorOccurred(ParseError error);
+		
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/Method.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Method {
+
+	private String name;
+	private boolean isStub;
+	private final LogModel model;
+	private List<Scope> scopes = new ArrayList<>();
+	private List<LogLine> logs = new ArrayList<>();
+	
+	Method(LogModel model) {
+		name = null;
+		isStub = false;
+		this.model = model;
+	}
+	
+	void init(String name, boolean isStub) {
+		this.name = name;
+		this.isStub = isStub;
+	}
+	
+	/**
+	 * Returns the name of the method
+	 * @return the method name
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Returns <code>true</code> if this is a stub method.
+	 * @return <code>true</code> if is stub, <code>false</code> otherwise
+	 */
+	public boolean isStub() {
+		return isStub;
+	}
+	
+	/**
+	 * Returns the model which holds this method.
+	 * @return model-object
+	 */
+	public LogModel getModel() {
+		return model;
+	}
+	
+	void add(Scope scope) {
+		scopes.add(scope);
+	}
+	
+	/**
+	 * Returns a list of all scopes inside a target method.
+	 * @return list of scopes
+	 */
+	public List<Scope> getScopes() {
+		return scopes;
+	}
+	
+	void add(LogLine log) {
+		logs.add(log);
+	}
+	
+	/**
+	 * Returns a list of all logs in the context of the method.
+	 * @return list of log lines
+	 */
+	public List<LogLine> getLogs() {
+		return Collections.unmodifiableList(logs);
+	}
+	
+	/**
+	 * The string representation of a method is its name.
+	 */
+	@Override
+	public String toString() {
+		return getName();
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/Node.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Node {
+
+	private final int number;
+	private final String name;
+	private final Scope scope;
+	private List<LogLine> logs = new ArrayList<>();
+	
+	
+	Node(int number, String name, Scope scope) {
+		this.number = number;
+		this.name = name;
+		this.scope = scope;
+	}
+	
+	/**
+	 * Returns the node number.
+	 * @return the node number
+	 */
+	public int getNumber() {
+		return number;
+	}
+	
+	/**
+	 * Returns the node name.
+	 * @return the node name
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Returns the parent scope.
+	 * @return the parent scope
+	 */
+	public Scope getScope() {
+		return scope;
+	}
+	
+	void add(LogLine log) {
+		logs.add(log);
+	}
+	
+	/**
+	 * Returns a list of all logs within a nodes context.
+	 * @return list of log lines
+	 */
+	public List<LogLine> getLogs() {
+		return Collections.unmodifiableList(logs);
+	}
+	
+	/**
+	 * The string represenation of a node is &quot;&lt;name&gt; (&lt;number&gt;)&quot;.
+	 */
+	@Override
+	public String toString() {
+		return getName() + "(" + getNumber() + ")";
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/Scope.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Scope {
+
+	private final String name;
+	private final Method method;
+	private List<Node> nodes = new ArrayList<>();
+	private List<LogLine> logs = new ArrayList<>();
+	
+	Scope(String name, Method method) {
+		this.name = name;
+		this.method = method;
+	}
+	
+	/**
+	 * Returns the scope name.
+	 * @return the scope name
+	 */
+	public String getName() {
+		return name;
+	}
+	
+	/**
+	 * Returns the parent method.
+	 * @return the parent method
+	 */
+	public Method getMethod() {
+		return method;
+	}
+	
+	void add(Node node) {
+		nodes.add(node);
+	}
+	
+	/**
+	 * Returns a list of all node-objects inside a scope.
+	 * @return list of nodes
+	 */
+	public List<Node> getNodes() {
+		return Collections.unmodifiableList(nodes);
+	}
+	
+	void add(LogLine log) {
+		logs.add(log);
+	}
+	
+	/**
+	 * Returns a list of all logs inside a scope.
+	 * @return list of log lines
+	 */
+	public List<LogLine> getLogs() {
+		return logs;
+	}
+	
+	/**
+	 * Returns the node inside a scope with the given number.
+	 * @param number node number
+	 * @return node-object
+	 */
+	public Node getNode(int number) {
+		for(Node node : nodes) {
+			if(node.getNumber() == number) return node;
+		}
+		return null;
+	}
+	
+	/**
+	 * The string representation of a scope is its name.
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return getName();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/Filter.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+
+public interface Filter {
+
+	/**
+	 * Sets the constraints for a filter.<br>
+	 * They can be every type of objects. In general these are strings, but it can also be
+	 * a Integer (like in the <code>NodeFilter</code>):<br>
+	 * <code>Filter nodeFilter = filterManager.getNodeFilter();
+	 * filter.setConstraints((String)nodeName, (Integer)nodeNumber);</code>
+	 * @param constraints filter constraints
+	 */
+	void setConstraints(Object ... constraints);
+	
+	/**
+	 * Indicates whether to keep a log line in the filter results, or not.
+	 * @param line log line which should be checked
+	 * @return <code>true</code> if the line should be kept, <code>false</code> otherwise
+	 */
+	boolean keep(LogLine line);
+	
+	/**
+	 * Activates or deactivates a filter. Deactivated filters will be ignored.
+	 * @param active <code>true</code> to activate, <code>false</code> to deactivate
+	 */
+	void setActive(boolean active);
+	
+	/**
+	 * Returns the activation status
+	 * @return <code>true</code> for an active filter, <code>false</code> otherwise
+	 */
+	boolean isActive();
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/FilterManager.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import com.oracle.graal.visualizer.logviewer.model.LogModel;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FilterManager {
+	
+	private final List<Filter> filters = new ArrayList<>();
+	private final Filter methodFilter, scopeFilter, nodeFilter, fulltextFilter;
+	
+	/**
+	 * Creates a new instance of the filter manager.
+	 */
+	public FilterManager() {
+		add(methodFilter = new MethodFilter());
+		add(scopeFilter = new ScopeFilter());
+		add(nodeFilter = new NodeFilter());
+		add(fulltextFilter = new FullTextFilter());
+	}
+	
+	/**
+	 * Executes a filtering process with the given log model as subject. Inactive filters will be ignored.
+	 * @param model subject
+	 * @return filtered list of log lines
+	 * @throws InterruptedException 
+	 */
+	public List<LogLine> execute(LogModel model) throws InterruptedException {
+		List<LogLine> input = model.getLogs();
+		List<LogLine> output = new ArrayList<>();
+		
+		for(LogLine line : input) {
+			if(Thread.interrupted()) throw new InterruptedException();
+			if(keep(line)) output.add(line);
+		}
+		
+		if(Thread.interrupted()) throw new InterruptedException();
+		
+		return output;
+	}
+	
+	private boolean keep(LogLine line) {
+		boolean keep = true;
+		for(Filter filter : filters) {
+			keep = keep && (!filter.isActive() || filter.keep(line));
+		}
+		return keep;
+	}
+	
+	private Filter add(Filter filter) {
+		filters.add(filter);
+		return filter;
+	}
+	
+	/**
+	 * Returns the instance of a method filter
+	 * @return method filter
+	 */
+	public Filter getMethodFilter() {
+		return methodFilter;
+	}
+	
+	/**
+	 * Returns the instance of a scope filter
+	 * @return scope filter
+	 */
+	public Filter getScopeFilter() {
+		return scopeFilter;
+	}
+	
+	/**
+	 * Returns the instance of a node filter
+	 * @return node filter
+	 */
+	public Filter getNodeFilter() {
+		return nodeFilter;
+	}
+	
+	/**
+	 * Returns the instance of a full text filter
+	 * @return full text filter
+	 */
+	public Filter getFullTextFilter() {
+		return fulltextFilter;
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/FullTextFilter.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class FullTextFilter implements Filter {
+
+	private Pattern p;
+	private boolean active = true;
+	
+	@Override
+	public void setConstraints(Object ... constraints) {
+        this.p = null;
+		for(Object constraint : constraints) {
+			setConstraint(constraint);
+		}
+	}
+	
+	private void setConstraint(Object constraint) {
+		if(constraint instanceof String) {
+			if(((String)constraint).trim().length() > 0) {
+				this.p = Pattern.compile((String)constraint);
+			}
+			else {
+				this.p = null;
+			}
+		}
+	}
+
+	@Override
+	public boolean keep(LogLine line) {
+		if(p == null) return true;
+		
+		Matcher matcher = p.matcher(line.getText());
+		return matcher.find();
+	}
+
+	@Override
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+	@Override
+	public boolean isActive() {
+		return active;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/MethodFilter.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class MethodFilter implements Filter {
+
+	private Pattern p;
+	private boolean active = true;
+	
+	@Override
+	public void setConstraints(Object ... constraints) {
+        this.p = null;
+		for(Object constraint : constraints) {
+			setConstraint(constraint);
+		}
+	}
+	
+	private void setConstraint(Object constraint) {
+		if(constraint instanceof String) {
+			if(((String)constraint).trim().length() > 0) {
+				this.p = Pattern.compile((String)constraint);
+			}
+			else {
+				this.p = null;
+			}
+		}
+	}
+
+	@Override
+	public boolean keep(LogLine line) {
+		if(p == null) return true;
+		
+		Matcher matcher = p.matcher(line.getMethod().getName());
+		return matcher.find();
+	}
+
+	@Override
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+	@Override
+	public boolean isActive() {
+		return active;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/NodeFilter.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class NodeFilter implements Filter {
+
+	private Pattern p;
+	private Integer nodeNum;
+	private boolean active = true;
+	
+	@Override
+	public void setConstraints(Object ... constraints) {
+        this.nodeNum = null;
+        this.p = null;
+		for(Object constraint : constraints) {
+			setConstraint(constraint);
+		}
+	}
+	
+	private void setConstraint(Object constraint) {
+		if(constraint instanceof String) {
+		
+			if(((String)constraint).trim().length() > 0) {
+				this.p = Pattern.compile((String)constraint);
+			}
+			else {
+				this.p = null;
+			}
+		}
+		else if(constraint instanceof Integer) {
+			this.nodeNum = (Integer)constraint;
+		}
+		
+	}
+
+	@Override
+	public boolean keep(LogLine line) {
+		if(p == null && nodeNum == null) return true; 
+		
+		if(line.getNode() == null) return false;
+		
+		boolean keep = false;
+		
+		if(p != null) {
+			Matcher matcher = p.matcher(line.getNode().getName());
+			keep = keep || matcher.find();
+		}
+		if(nodeNum != null) {
+			keep = keep || nodeNum.equals(line.getNode().getNumber());
+		}
+		
+		return keep;		
+	}
+
+	@Override
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+	@Override
+	public boolean isActive() {
+		return active;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/filter/ScopeFilter.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.filter;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class ScopeFilter implements Filter {
+
+	private Pattern p;
+	private boolean active = true;
+	
+	@Override
+	public void setConstraints(Object ... constraints) {
+        this.p = null;
+		for(Object constraint : constraints) {
+			setConstraint(constraint);
+		}
+	}
+	
+	private void setConstraint(Object constraint) {
+		if(constraint instanceof String) {
+			if(((String)constraint).trim().length() > 0) {
+				this.p = Pattern.compile((String)constraint);
+			}
+			else {
+				this.p = null;
+			}
+		}
+	}
+
+	@Override
+	public boolean keep(LogLine line) {
+		if(p == null) return true;
+        
+        if(line.getScope() == null) return false;
+		
+		Matcher matcher = p.matcher(line.getScope().getName());
+		return matcher.find();
+	}
+
+	@Override
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+	@Override
+	public boolean isActive() {
+		return active;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/FileLine.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.io;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+
+public class FileLine implements CharSequence {
+
+	private final SeekableFile seekableFile;
+	private WeakReference<String> cache;
+	public final long off;
+	public final int len;
+	
+	public FileLine(SeekableFile seekableFile, long off, int len) {
+		this.seekableFile = seekableFile;
+		this.off = off;
+		this.len = len;
+	}
+	
+	@Override
+	public String toString() {
+		String line = null;
+		
+		if(cache != null) line = cache.get();
+		
+		if(line == null) {
+			try {
+				line = seekableFile.read(this);
+				cache = new WeakReference<>(line);
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		
+		return line;
+	}
+
+	@Override
+	public int length() {
+		return len;
+	}
+
+	@Override
+	public char charAt(int index) {
+		String line = toString();
+		return line != null ? line.charAt(index) : 0;
+	}
+
+	@Override
+	public CharSequence subSequence(int start, int end) {
+		String line = toString();
+		return line != null ? line.subSequence(start, end) : "";
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/ProgressMonitor.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.io;
+
+public interface ProgressMonitor {
+
+	/**
+	 * Triggered when some work has been done.<br><br>
+	 * <b>Attention</b>: This method runs on the same thread as the reading process.
+	 * If time-consuming tasks should be executed, please consider multithreading.
+	 * @param percentage Value in range between 0 and 1 to indicate how much work has been done.
+	 */
+	public void worked(float percentage);
+	
+	/**
+	 * Triggered when work is done completely.<br><br>
+	 * <b>Attention</b>: This method runs on the same thread as the reading process.
+	 * If time-consuming tasks should be executed, please consider multithreading.
+	 */
+	public void finished();
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/SeekableFile.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.io;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SeekableFile implements Closeable {
+
+	private final RandomAccessFile raf;
+	private List<FileLine> lines = new ArrayList<>();
+	
+	SeekableFile(File file) throws FileNotFoundException {
+		raf = new RandomAccessFile(file, "r");
+	}
+	
+	void addLine(long off, int len) {
+		lines.add(new FileLine(this, off, len));
+	}
+	
+	public int size() {
+		return lines.size();
+	}
+	
+	public FileLine get(int lineNum) throws IOException {
+		FileLine line = lines.get(lineNum);
+		return line;
+	}
+	
+	String read(FileLine line) throws IOException {
+		if(line == null) throw new IllegalArgumentException("line is null");
+		raf.seek(line.off);
+
+		byte [] buf = new byte[line.len];
+		
+		if(raf.read(buf) != line.len) throw new IOException("error while reading line");
+		
+		return new String(buf);
+	}
+
+	@Override
+	public void close() throws IOException {
+		raf.close();
+	}
+	
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/model/io/SeekableFileReader.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.model.io;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+public class SeekableFileReader extends Reader {
+	
+	public static final int DEFAULT_GAP = 1024; // in bytes
+
+	private final FileReader reader;
+	private SeekableFile seekableFile;
+	private ProgressMonitor monitor;
+	private long filelen;
+	private int gap;
+	
+	public SeekableFileReader(File file) throws IOException {
+		super(file);
+		reader = new FileReader(file);
+		seekableFile = new SeekableFile(file);
+	}
+	
+	public SeekableFileReader(File file, ProgressMonitor monitor, int gap) throws IOException {
+		this(file);
+		this.monitor = monitor;
+		this.filelen = file.length();
+		this.gap = gap;
+	}
+	
+	public SeekableFileReader(File file, ProgressMonitor monitor) throws IOException {
+		this(file, monitor, DEFAULT_GAP);
+	}
+	
+	public SeekableFile getSeekableFile() {
+		return seekableFile;
+	}
+
+    @Override
+	public void close() throws IOException {
+		reader.close();		
+	}
+	
+	private long bytes = 0;
+	private boolean skipLF = false;
+	private long off;
+	private long lastGapped = 0;
+	private boolean finished = false;
+
+	@Override
+	public int read(char[] cbuf, int offset, int length) throws IOException {
+		
+		int l = reader.read(cbuf, offset, length);
+		
+		if(l == -1 && !finished) {
+			seekableFile.addLine(off, (int)(bytes-off));
+			finished = true;
+			if(monitor != null) {
+				monitor.worked(1);
+				monitor.finished();
+			}
+		}
+		
+		for(int i = 0; i < l; ++i) {
+			Character ch = new Character(cbuf[i]);
+			int chlen = ch.toString().getBytes(reader.getEncoding()).length;
+				
+			if(skipLF && ch != '\n') {
+				seekableFile.addLine(off, (int)(bytes-off-chlen));
+				off = bytes;
+				skipLF = false;
+			}
+			
+			bytes += chlen;
+			
+			if(monitor != null) {
+				if(bytes > lastGapped+gap) {
+					lastGapped = bytes;
+					monitor.worked(((float)bytes)/((float)filelen));
+				}
+			}
+			
+			if(ch == '\r') {
+				skipLF = true;
+			}
+			if(ch == '\n') {
+				seekableFile.addLine(off, (int)(bytes-off-(skipLF ? 2*chlen : chlen)));
+				off = bytes;
+				skipLF = false;
+			}
+		}
+		
+		return l;
+	}
+	
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/BookmarkDialog.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.List;
+import javax.swing.*;
+
+public class BookmarkDialog extends JDialog {
+    
+    private JList lstBookmarks;
+    private List<LogLine> logLines;
+    
+    public BookmarkDialog(List<LogLine> bookmarks, Window parent) {
+        super(parent, JDialog.ModalityType.APPLICATION_MODAL);
+        
+        this.logLines = bookmarks;
+        
+        DefaultListModel mdlBookmarks = new DefaultListModel();
+        lstBookmarks = new JList(mdlBookmarks);
+        JScrollPane jspBookmarks = new JScrollPane(lstBookmarks);
+        
+        for (LogLine bookmark : bookmarks) {
+            mdlBookmarks.addElement(bookmark.getLineNumber() + ": Method " + bookmark.getMethod() + " - Scope " + bookmark.getScope() + " - " + bookmark.getText());
+        }
+        
+        JButton btnOk = new JButton("Go to");
+        JButton btnCancel = new JButton("Cancel");
+
+        // init listeners
+        lstBookmarks.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseClicked(MouseEvent e) {
+                if (e.getClickCount() == 2) {
+                    close();
+                }
+            }
+        });
+        
+        btnOk.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                if (lstBookmarks.isSelectionEmpty())
+                    return;
+                close();
+            }
+        });
+        btnCancel.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                lstBookmarks.clearSelection();
+                close();
+            }
+        });
+        
+        // build layout
+        JPanel pnlButtons = new JPanel();
+        
+        pnlButtons.setLayout(new GridLayout(1, 2));
+        pnlButtons.add(btnOk);
+        pnlButtons.add(btnCancel);
+        
+        this.setLayout(new BorderLayout());
+        this.add(jspBookmarks, BorderLayout.CENTER);
+        this.add(pnlButtons, BorderLayout.SOUTH);
+        
+        this.pack();
+        this.setMinimumSize(new Dimension(600, this.getPreferredSize().height));
+        this.setLocationRelativeTo(parent);
+        this.setResizable(false);
+        this.setVisible(true);
+    }
+    
+    public LogLine getTarget() {
+        if (lstBookmarks.isSelectionEmpty())
+            return null;
+        return logLines.get(lstBookmarks.getSelectedIndex());
+    }
+    
+    private void close() {
+        this.setVisible(false);
+        this.dispose();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/BookmarkableLogViewer.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultHighlighter;
+import javax.swing.text.Highlighter;
+import javax.swing.text.JTextComponent;
+import org.openide.util.Exceptions;
+
+public class BookmarkableLogViewer extends JPanel {
+
+    private static final Color BOOKMARK_COLOR = Color.CYAN;
+    
+    private static final Highlighter.HighlightPainter BOOKMARK_PAINTER =
+            new DefaultHighlighter.DefaultHighlightPainter(BOOKMARK_COLOR);
+    
+    private JTextPane txpText;
+    private JTextPane txpLines;
+    private Highlighter textHighlighter;
+    private Highlighter lineHighlighter;
+    private FontMetrics fm;
+    private Map<Integer, Bookmark> bookmarks = new TreeMap<>();
+    private List<LogLine> logLines = new ArrayList<>();
+
+    public BookmarkableLogViewer() {
+        init();
+    }
+
+    private void init() {
+        txpText = new JTextPane();
+        txpLines = new JTextPane();
+
+        // needed for correct layouting
+        Insets ins = txpLines.getInsets();
+        txpLines.setMargin(new Insets(ins.top + 1, ins.left, ins.bottom, ins.right));
+
+        textHighlighter = new BookmarkHighlighter();
+        lineHighlighter = new BookmarkHighlighter();
+
+        txpText.setHighlighter(textHighlighter);
+        //txpText.setMinimumSize(new Dimension(100, 100));
+        txpText.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
+        txpText.setEditable(false);
+
+        txpLines.setHighlighter(lineHighlighter);
+        txpLines.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
+        txpLines.setBackground(Color.LIGHT_GRAY);
+        txpLines.setEnabled(false);
+        txpLines.setForeground(Color.BLACK);
+        txpLines.addMouseListener(mouseInputListener);
+
+        fm = txpText.getFontMetrics(txpText.getFont());
+
+        JPanel pnlBookmarks = new JPanel();
+        pnlBookmarks.setLayout(new BorderLayout());
+        pnlBookmarks.add(txpText, BorderLayout.CENTER);
+
+        JScrollPane jspBookmarks = new JScrollPane(pnlBookmarks);
+        jspBookmarks.setRowHeaderView(txpLines);
+        jspBookmarks.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+        jspBookmarks.getVerticalScrollBar().setUnitIncrement(15);
+
+        this.setLayout(new BorderLayout());
+        this.add(jspBookmarks, BorderLayout.CENTER);
+    }
+   
+    public int getCurrentlyDisplayedTopLine() {
+        Rectangle view = txpText.getVisibleRect();
+        return getAbsoluteLine((int) Math.ceil(view.y/fm.getHeight()));
+    }
+    
+    public int getCurrentTopLine() {
+        return logLines.get(0).getLineNumber();
+    }
+    
+    public int getCurrentBottomLine() {
+        return logLines.get(logLines.size()-1).getLineNumber();
+    }
+
+    public void clearLogLines() {
+        this.logLines = new ArrayList<>();
+        txpText.setText("");
+        txpLines.setText("");
+        clearHighlighter();
+    }
+
+    public void setLogLines(List<LogLine> logLines) {
+        this.logLines = logLines;
+
+        clearHighlighter();
+        clearLineNumbers();
+        String text = "";
+        for (int i = 0; i < logLines.size(); i++) {
+            text += logLines.get(i).getText();
+            if (i < logLines.size() - 1) {
+                text += "\n";
+            }
+        }
+        txpText.setText(text);
+        setLineNumbers();
+   
+        txpText.setCaretPosition(0);
+        txpLines.setCaretPosition(0);
+
+        for (int bookmark : bookmarks.keySet()) {
+            if (bookmark < logLines.get(0).getLineNumber()) {
+                continue;
+            }
+            if (bookmark > logLines.get(logLines.size() - 1).getLineNumber()) {
+                break;
+            }
+
+            int line = getRelativeLine(bookmark);
+
+            addHighlight(logLines.get(line));
+        }
+    }
+
+    public void setLogLines(List<LogLine> logLines, int focus) {
+        setLogLines(logLines);
+        
+        //does not work for some reason - jtextpane jumps to caret position afterwards
+        //moveToBookmark(focus);
+        
+        //workaround - set caret position bevore moving
+        Rectangle visible = txpText.getVisibleRect();
+        int visibleLines = (int)(Math.ceil(visible.height/fm.getHeight()));
+
+        String text = txpText.getText();
+        int line = logLines.get(0).getLineNumber();
+        for (int i = 0; i < text.length(); i++) {
+            if (text.charAt(i) == '\n')
+                line++;
+            if (line == focus+visibleLines || i == text.length() - 1) {
+                txpText.setCaretPosition(i);
+                break;
+            }
+        }
+        moveToBookmark(focus);
+    }
+
+    public List<LogLine> getBookmarkedLines() {
+        List<LogLine> lines = new ArrayList<>();
+        for (int bookmark : bookmarks.keySet()) {
+            lines.add(bookmarks.get(bookmark).logLine);
+        }
+        return lines;
+    }
+
+    public int tryLastBookmark() {
+        int line = getCurrentlyDisplayedTopLine();
+        
+        int firstShownLine = getCurrentTopLine();
+
+        int bookmarkKey = -1;
+        for (int key : bookmarks.keySet()) {
+            if (key >= line) {
+                break;
+            }
+
+            bookmarkKey = key;
+        }
+
+        if (bookmarkKey >= firstShownLine) {
+            moveToBookmark(bookmarkKey);
+            return -1;
+        }
+
+        return bookmarkKey;
+    }
+
+    public int tryNextBookmark() {
+        Rectangle visible = txpText.getVisibleRect();
+        int lastLine = (int) Math.floor((visible.y + visible.height) / fm.getHeight());
+        lastLine = getAbsoluteLine(lastLine);
+
+        int lastShownLine = getCurrentBottomLine();
+
+        int bookmarkKey = -1;
+        for (int key : bookmarks.keySet()) {
+            if (key > lastLine) {
+                bookmarkKey = key;
+                break;
+            }
+            if (key > lastShownLine) {
+                break;
+            }
+        }
+
+        if (bookmarkKey > 0 && bookmarkKey <= lastShownLine) {
+            moveToBookmark(bookmarkKey);
+            return -1;
+        }
+
+        return bookmarkKey;
+    }
+
+    private void moveToBookmark(int line) {
+        int relLine = getRelativeLine(line);
+        Rectangle visible = txpText.getVisibleRect();
+        Rectangle position = new Rectangle(0, relLine * fm.getHeight(), visible.width, visible.height);
+        txpText.scrollRectToVisible(position);
+    }
+
+    private int getAbsoluteLine(int line) {
+        return logLines.get(0).getLineNumber() + line;
+    }
+
+    private int getRelativeLine(int line) {
+        return line - logLines.get(0).getLineNumber();
+    }
+
+    private int getStartOffset(JTextComponent component, int line) {
+        return component.getDocument().getDefaultRootElement().getElement(line).getStartOffset();
+    }
+
+    private int getEndOffset(JTextComponent component, int line) {
+        return component.getDocument().getDefaultRootElement().getElement(line).getEndOffset();
+    }
+
+    private void addHighlight(LogLine logLine) {
+        try {
+            int line = logLine.getLineNumber();
+            int relativeLine = getRelativeLine(line);
+
+            Object hl1 = textHighlighter.addHighlight(getStartOffset(txpText, relativeLine), getEndOffset(txpText, relativeLine), BOOKMARK_PAINTER);
+            Object hl2 = lineHighlighter.addHighlight(getStartOffset(txpLines, relativeLine), getEndOffset(txpLines, relativeLine), BOOKMARK_PAINTER);
+            bookmarks.put(line, new Bookmark(logLine, hl1, hl2));
+        } catch (BadLocationException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+    }
+
+    private void removeHighlight(int line) {
+        int abs = getAbsoluteLine(line);
+        Bookmark bookmark = bookmarks.get(abs);
+        textHighlighter.removeHighlight(bookmark.hl1);
+        lineHighlighter.removeHighlight(bookmark.hl2);
+        bookmarks.remove(abs);
+    }
+
+    public void clearBookmarks() {
+        bookmarks = new TreeMap<>();
+        clearHighlighter();
+    }
+
+    private void clearHighlighter() {
+        textHighlighter.removeAllHighlights();
+        lineHighlighter.removeAllHighlights();
+    }
+
+    private void clearLineNumbers() {
+        txpLines.setText("");
+    }
+
+    private void setLineNumbers() {
+        clearLineNumbers();
+
+        if (logLines.isEmpty()) {
+            return;
+        }
+
+        int colCnt = String.valueOf(logLines.get(logLines.size() - 1).getLineNumber()).length() + 2;
+
+        int firstNr = logLines.get(0).getLineNumber();
+        String text = String.format("%" + colCnt + "s", firstNr + " ");
+        for (int i = 1; i < logLines.size(); i++) {
+            text += "\n";
+            text += String.format("%" + colCnt + "s", (firstNr + i) + " ");
+        }
+        txpLines.setText(text);
+    }
+
+    private MouseListener mouseInputListener = new MouseAdapter() {
+
+        @Override
+        public void mouseClicked(MouseEvent me) {
+            if (txpLines.getText().length() == 0) {
+                return;
+            }
+            if (me.getClickCount() == 2) {
+                int caretPos = txpLines.getCaretPosition();
+
+                int lineOffset = txpLines.getDocument().getDefaultRootElement().getElementIndex(caretPos);
+                if (txpLines.getText().charAt(caretPos - 1) == '\n') {
+                    lineOffset--;
+                }
+
+                if (bookmarks.containsKey(getAbsoluteLine(lineOffset))) {
+                    removeHighlight(lineOffset);
+                } else {
+                    addHighlight(logLines.get(lineOffset));
+                }
+            }
+        }
+    };
+
+    class Bookmark {
+
+        public final LogLine logLine;
+        public final Object hl1;
+        public final Object hl2;
+
+        public Bookmark(LogLine logLine, Object hl1, Object hl2) {
+            this.logLine = logLine;
+            this.hl1 = hl1;
+            this.hl2 = hl2;
+        }
+    }
+
+    class BookmarkHighlighter extends DefaultHighlighter {
+
+        private JTextComponent component;
+
+        @Override
+        public void install(JTextComponent component) {
+            super.install(component);
+            this.component = component;
+        }
+
+        @Override
+        public void deinstall(JTextComponent component) {
+            super.deinstall(component);
+            this.component = null;
+        }
+
+        @Override
+        public void paint(Graphics g) {
+            Highlighter.Highlight[] highlights = getHighlights();
+
+            for (int i = 0; i < highlights.length; i++) {
+                Highlighter.Highlight hl = highlights[i];
+                Rectangle bg = component.getBounds();
+                Insets insets = component.getInsets();
+                bg.x = insets.left;
+                bg.y = insets.top;
+                bg.height = insets.top + insets.bottom;
+                Highlighter.HighlightPainter painter = hl.getPainter();
+                painter.paint(g, hl.getStartOffset(), hl.getEndOffset(), bg, component);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/ImportLogErrorDialog.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene;
+
+import com.oracle.graal.visualizer.logviewer.model.LogParser;
+import java.awt.Component;
+import java.util.List;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+public class ImportLogErrorDialog {
+    
+    public static void showDialog(Component parent, List<LogParser.ParseError> errors) {
+        JTextArea txaErrors = new JTextArea();
+        
+        for (LogParser.ParseError error : errors) {
+            txaErrors.append("Error at line " + error.getLineNumber());
+            txaErrors.append(": " + error.getMessage());
+            txaErrors.append("\n");
+            txaErrors.append("Log line: " + error.getLine());
+            txaErrors.append("\n");
+        }
+        
+        JScrollPane scpErrors = new JScrollPane(txaErrors);
+        
+        JOptionPane.showMessageDialog(parent, scpErrors, "Parse errors", JOptionPane.ERROR_MESSAGE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/LogScene.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,671 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+import com.oracle.graal.visualizer.logviewer.model.LogModel;
+import com.oracle.graal.visualizer.logviewer.model.LogParser;
+import com.oracle.graal.visualizer.logviewer.model.filter.Filter;
+import com.oracle.graal.visualizer.logviewer.model.filter.FilterManager;
+import com.oracle.graal.visualizer.logviewer.model.io.ProgressMonitor;
+import com.oracle.graal.visualizer.logviewer.scene.model.LogTableModel;
+import com.oracle.graal.visualizer.logviewer.scene.model.TableLine;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.regex.PatternSyntaxException;
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import org.openide.util.Exceptions;
+import org.openide.util.NbPreferences;
+import sun.awt.CausedFocusEvent;
+
+public class LogScene extends JPanel {
+    private static final String PREFERENCE_DIR = "dir";
+    
+    private static final String ICON_PREFIX = "/com/oracle/graal/visualizer/logviewer/scene/icons/";
+    private static final String ICON_ARROW_DOWN = ICON_PREFIX + "arrow_down.png";
+    private static final String ICON_ARROW_UP = ICON_PREFIX + "arrow_up.png";
+    private static final String ICON_BOOKMARK_BACK = ICON_PREFIX + "bookmark_back.png";
+    private static final String ICON_BOOKMARK_FWD = ICON_PREFIX + "bookmark_forward.png";
+    private static final String ICON_BOOKMARK_LIST = ICON_PREFIX + "bookmark_list.png";
+    private static final String ICON_LOAD = ICON_PREFIX + "loading.gif";
+    
+    private static final ImageIcon IMGICON_LOAD = new ImageIcon(LogScene.class.getResource(ICON_LOAD));
+    
+    private static final int LOG_LINES = 50;
+    private static final int KEYSTROKE_RATE = 100; // rate at which the keystrokes are checked
+    private static final int KEYSTROKE_TRESHOLD = 400; // time in ms after which a search is triggered
+            
+    private FilterManager filterManager;
+    private Thread filterRunThread;
+    
+    private int timeSinceLastKeystroke = -1;
+    
+    private JLabel lblMessage;
+    private JLabel lblIcon;
+    
+    private JLabel lblMethodFilter;
+    private JLabel lblScopeFilter;
+    private JLabel lblNodeFilter;
+    private JLabel lblFulltextFilter;
+    private JTextField txfMethodFilter;
+    private JTextField txfScopeFilter;
+    private JTextField txfNodeFilter;
+    private JTextField txfFulltextFilter;
+    
+    private JTable tblResult;
+    private LogTableModel tblResultModel;
+    
+    private BookmarkableLogViewer logViewer;
+    private JButton btnBookmarkBack;
+    private JButton btnBookmarkFwd;
+    private JButton btnBookmarkList;
+    private JButton btnLoadMoreUp;
+    private JButton btnLoadMoreDown;
+    
+    private LogParser parser = new LogParser();
+    private LogModel logModel = null;
+    private LogStatus logStatus = LogStatus.NO_LOG;
+    
+    private static LogScene instance;
+    
+    private enum LogStatus {
+        NO_LOG, LOADING, ACTIVE
+    }
+
+    public static LogScene getInstance() {
+        return instance;
+    }
+    
+    public LogScene() {
+        initComponents();
+    }
+    
+    private void initComponents() {
+        filterManager = new FilterManager();
+        
+        lblMessage = new JLabel("No logfile loaded.");
+        lblIcon = new JLabel("");
+        
+        // Initialize filter components
+        lblMethodFilter = new JLabel("Target Method:");
+        lblScopeFilter = new JLabel("Scope:");
+        lblNodeFilter = new JLabel("Node:");
+        lblFulltextFilter = new JLabel("Fulltext:");
+        
+        txfMethodFilter = new JTextField();
+        txfScopeFilter = new JTextField();
+        txfNodeFilter = new JTextField();
+        txfFulltextFilter = new JTextField();
+        
+        tblResultModel = new LogTableModel();
+        tblResult = new JTable(tblResultModel);
+        tblResult.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        tblResult.getTableHeader().setReorderingAllowed(false);
+        tblResult.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+        
+        Dimension dim = tblResult.getPreferredScrollableViewportSize();
+        tblResult.setPreferredScrollableViewportSize(new Dimension(dim.width, 10*tblResult.getRowHeight() + tblResult.getTableHeader().getHeight()));
+        JScrollPane scpTblResult = new JScrollPane(tblResult);
+        scpTblResult.setMinimumSize(new Dimension(dim.width, 10*tblResult.getRowHeight() + tblResult.getTableHeader().getHeight()));
+        
+        logViewer = new BookmarkableLogViewer();
+        
+        btnLoadMoreUp = new JButton(new ImageIcon(LogScene.class.getResource(ICON_ARROW_UP)));
+        btnLoadMoreDown = new JButton(new ImageIcon(LogScene.class.getResource(ICON_ARROW_DOWN)));
+        
+        btnLoadMoreUp.setFocusable(false);
+        btnLoadMoreUp.setToolTipText("Load more previous log lines");
+        
+        btnLoadMoreDown.setFocusable(false);
+        btnLoadMoreDown.setToolTipText("Load more following log lines");
+        
+        btnBookmarkBack = new JButton(new ImageIcon(LogScene.class.getResource(ICON_BOOKMARK_BACK)));
+        btnBookmarkList = new JButton(new ImageIcon(LogScene.class.getResource(ICON_BOOKMARK_LIST)));
+        btnBookmarkFwd = new JButton(new ImageIcon(LogScene.class.getResource(ICON_BOOKMARK_FWD)));
+        
+        btnBookmarkBack.setFocusable(false);
+        btnBookmarkBack.setToolTipText("Navigate to the last bookmark.");
+        
+        btnBookmarkFwd.setFocusable(false);
+        btnBookmarkFwd.setToolTipText("Navigate to the next bookmark.");
+        
+        btnBookmarkList.setFocusable(false);
+        btnBookmarkList.setToolTipText("List all known bookmarks.");
+        
+        JPanel pnl = new JPanel();
+        pnl.setLayout(new GridBagLayout());
+        pnl.setOpaque(false);
+        
+        JPanel logViewerPanel = new JPanel();
+        logViewerPanel.setLayout(new GridBagLayout());
+        logViewerPanel.setOpaque(false);
+        
+        JPanel messagePanel = new JPanel();
+        messagePanel.setLayout(new BoxLayout(messagePanel, BoxLayout.LINE_AXIS));
+        messagePanel.setOpaque(false);
+        
+        // Initialize Listeners
+        initListeners();
+        
+        // Layout components
+        GridBagConstraints gbc = new GridBagConstraints();
+        
+        messagePanel.add(lblMessage);
+        messagePanel.add(Box.createHorizontalGlue());
+        messagePanel.add(lblIcon);
+        
+        Insets standardInsets = gbc.insets;
+        
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.anchor = GridBagConstraints.WEST;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        gbc.weightx = 1;
+        gbc.weighty = 0;
+        gbc.gridwidth = 2;
+        gbc.insets = new Insets(2, 0, 2, 0);
+        pnl.add(messagePanel, gbc);
+        
+        gbc.fill = GridBagConstraints.NONE;
+        gbc.gridwidth = 1;
+        gbc.weightx = 0;
+        gbc.weighty = 0;
+        gbc.gridy++;
+        gbc.insets = standardInsets;
+        pnl.add(lblMethodFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(lblScopeFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(lblNodeFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(lblFulltextFilter, gbc);
+        
+        gbc.gridx++;
+        gbc.gridy = 1;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        gbc.weightx = 0.75;
+        pnl.add(txfMethodFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(txfScopeFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(txfNodeFilter, gbc);
+        
+        gbc.gridy++;
+        pnl.add(txfFulltextFilter, gbc);
+        
+        gbc.gridx = 0;
+        //gbc.gridy++;
+        gbc.gridwidth = 2;
+        gbc.weightx = 1;
+        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
+        //pnl.add(btnSearch, gbc);
+        
+        gbc.gridy++;
+        pnl.add(scpTblResult, gbc);
+        
+        gbc.gridy++;
+        gbc.weighty = 1;
+        gbc.fill = GridBagConstraints.BOTH;
+        pnl.add(logViewerPanel, gbc);
+        
+        gbc = new GridBagConstraints();
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.gridheight = 6;
+        gbc.weightx = 1;
+        gbc.weighty = 1;
+        gbc.fill = GridBagConstraints.BOTH;
+        logViewerPanel.add(logViewer, gbc);
+        
+        gbc.gridx++;
+        gbc.weightx = 0;
+        gbc.weighty = 0;
+        gbc.fill = GridBagConstraints.NONE;
+        gbc.anchor = GridBagConstraints.PAGE_START;
+        gbc.gridheight = 1;
+        logViewerPanel.add(btnLoadMoreUp, gbc);
+        
+        gbc.gridy++;
+        logViewerPanel.add(btnLoadMoreDown, gbc);
+        
+        gbc.gridy++;
+        logViewerPanel.add(Box.createRigidArea(btnLoadMoreUp.getSize()));
+        
+        gbc.gridy++;
+        logViewerPanel.add(btnBookmarkBack, gbc);
+        
+        gbc.gridy++;
+        logViewerPanel.add(btnBookmarkFwd, gbc);
+        
+        gbc.gridy++;
+        logViewerPanel.add(btnBookmarkList, gbc);
+        
+        this.setLayout(new BorderLayout());
+        this.add(pnl, BorderLayout.CENTER);
+        
+        Timer keyTimer = new Timer();
+        keyTimer.scheduleAtFixedRate(new KeystrokeTimer(), KEYSTROKE_RATE, KEYSTROKE_RATE);
+        
+        LogScene.instance = this;
+    }
+    
+    private void initListeners() {
+        txfMethodFilter.addKeyListener(new FilterKeyListener());
+        txfScopeFilter.addKeyListener(new FilterKeyListener());
+        txfNodeFilter.addKeyListener(new FilterKeyListener());
+        txfFulltextFilter.addKeyListener(new FilterKeyListener());
+        
+        txfMethodFilter.addFocusListener(new FilterFocusListener());
+        txfScopeFilter.addFocusListener(new FilterFocusListener());
+        txfNodeFilter.addFocusListener(new FilterFocusListener());
+        txfFulltextFilter.addFocusListener(new FilterFocusListener());
+        
+        btnLoadMoreUp.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                int line = logViewer.getCurrentlyDisplayedTopLine();
+                int top = logViewer.getCurrentTopLine();
+                int bottom = logViewer.getCurrentBottomLine();
+                logViewer.setLogLines(logModel.range(line, line - top + LOG_LINES, bottom - line), line); 
+            } 
+        });
+        
+        btnLoadMoreDown.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                int line = logViewer.getCurrentlyDisplayedTopLine();
+                int top = logViewer.getCurrentTopLine();
+                int bottom = logViewer.getCurrentBottomLine();
+                logViewer.setLogLines(logModel.range(line, line - top, bottom - line + LOG_LINES), line); 
+            } 
+        });
+        
+        btnBookmarkBack.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                int result = logViewer.tryLastBookmark();
+                if (result >= 0) {
+                    tblResult.clearSelection();
+                    logViewer.setLogLines(logModel.range(result, LOG_LINES, LOG_LINES), result); 
+                }
+            }
+        });
+        
+        btnBookmarkFwd.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                int result = logViewer.tryNextBookmark();
+                if (result >= 0) {
+                    tblResult.clearSelection();
+                    logViewer.setLogLines(logModel.range(result, LOG_LINES, LOG_LINES), result);
+                }
+            }
+        });
+        
+        btnBookmarkList.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent ae) {
+                List<LogLine> bookmarkedLines = logViewer.getBookmarkedLines();
+                if (bookmarkedLines.size() > 0) {
+                    BookmarkDialog bd = new BookmarkDialog(bookmarkedLines, null);
+                    if (bd.getTarget() != null) {
+                        LogLine target = bd.getTarget();
+                        int line = target.getLineNumber();
+                        logViewer.setLogLines(logModel.range(line, LOG_LINES, LOG_LINES), line); 
+                    }
+                } else {
+                    JOptionPane.showMessageDialog(LogScene.this, "No bookmarks set.", "", JOptionPane.INFORMATION_MESSAGE);
+                }
+            }
+        });
+        
+        tblResult.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+            @Override
+            public void valueChanged(ListSelectionEvent lse) {
+                if (tblResult.getSelectedRow() == -1) {
+                    logViewer.clearLogLines();
+                    return;
+                }
+                
+                TableLine selectedLine = tblResultModel.getTableLine(tblResult.getSelectedRow());
+                int firstLine = selectedLine.getFirstLine();
+                int lastLine = selectedLine.getLastLine();
+                
+                if (firstLine == lastLine) { 
+                    // only display selected line
+                    List<LogLine> line = new ArrayList<>();
+                    line.add(selectedLine.getLogLine());
+                    logViewer.setLogLines(line);
+                } else {
+                    // display selected range
+                    int pre = firstLine==lastLine?LOG_LINES:selectedLine.getLogLine().getLineNumber()-firstLine;
+                    int post = firstLine==lastLine?LOG_LINES:lastLine-selectedLine.getLogLine().getLineNumber();
+
+                    logViewer.setLogLines(logModel.range(selectedLine.getLogLine(), pre, post));           
+                }
+            }
+        });
+    }
+    
+    private boolean executeFilters() {
+        if (logStatus == LogStatus.NO_LOG) {
+            loadLogFile();
+            return false;
+        }
+        if (logStatus == LogStatus.LOADING) {
+            return false;
+        }
+
+        boolean execute = trySetFilter(filterManager.getMethodFilter(), txfMethodFilter.getText().trim(), lblMethodFilter);
+        execute = trySetFilter(filterManager.getScopeFilter(), txfScopeFilter.getText().trim(), lblScopeFilter) || execute;
+        try {
+            // node number
+            int node = Integer.parseInt(txfNodeFilter.getText().trim());
+            execute = trySetFilter(filterManager.getNodeFilter(), node, lblNodeFilter) || execute;
+        } catch (Exception e) {
+            // node name
+            execute = trySetFilter(filterManager.getNodeFilter(), txfNodeFilter.getText().trim(), lblNodeFilter) || execute;
+        }
+        execute = trySetFilter(filterManager.getFullTextFilter(), txfFulltextFilter.getText().trim(), lblFulltextFilter) || execute;
+
+        if (!execute)
+            return true;
+        
+        tryInterruptFilter();
+
+        filterRunThread = new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    List<LogLine> result = filterManager.execute(logModel);
+                    lblIcon.setIcon(null);
+
+                    if (!Thread.interrupted())
+                        buildTableEntries(result);
+                } catch (InterruptedException e) {
+                }
+            }
+
+        });
+        lblIcon.setIcon(IMGICON_LOAD);
+        filterRunThread.start();
+        
+        return true;
+    }
+    
+    private boolean trySetFilter(Filter filter, Object constraint, JLabel marker) {
+        try {
+            filter.setConstraints(constraint);
+            marker.setForeground(Color.BLACK);
+            return constraint != null && (!(constraint instanceof String) || (constraint instanceof String && ((String)constraint).trim().length() > 0));
+        } catch (PatternSyntaxException e) {
+            filter.setConstraints(new Object[]{});
+            marker.setForeground(Color.RED);
+            return false;
+        }
+    }
+    
+    private void tryInterruptFilter() {
+        if (filterRunThread != null && (filterRunThread.isAlive() || !filterRunThread.isInterrupted())) {
+            lblIcon.setIcon(null);
+            filterRunThread.interrupt();
+        }
+    }
+    
+    private void buildTableEntries(List<LogLine> filterResult) {
+        List<TableLine> tableEntries;
+        
+        int methodLength = txfMethodFilter.getText().trim().length();
+        int scopeLength = txfScopeFilter.getText().trim().length();
+        int nodeLength = txfNodeFilter.getText().trim().length();
+        int fulltextLength = txfFulltextFilter.getText().trim().length();
+        
+        boolean preventGrouping = nodeLength != 0 || fulltextLength != 0;
+        
+        if (!preventGrouping && methodLength > 0 && scopeLength == 0) {
+            tableEntries = groupByMethod(filterResult);
+        } else if (!preventGrouping && scopeLength > 0) {
+            tableEntries = groupByScope(filterResult);
+        } else {
+            tableEntries = showAllLines(filterResult);
+        }
+        
+        tblResultModel.setLogEntries(tableEntries);
+        
+        int width = 0;
+        for (int i = 0; i < tableEntries.size(); i++) {
+            TableCellRenderer tcr = tblResult.getCellRenderer(i, 0);
+            Component c = tcr.getTableCellRendererComponent(tblResult, tblResultModel.getValueAt(i, 0), false, false, i, 0);
+            if (c instanceof JLabel) {
+                JLabel l = (JLabel) c;
+                FontMetrics fm = l.getFontMetrics(l.getFont());
+                width = Math.max(width, fm.stringWidth(l.getText()));
+            }
+        }
+       
+        // proper resizing of column
+        // setWidth and setPreferredWidth do not trigger resize
+        TableColumn col = tblResult.getColumnModel().getColumn(0);
+        col.setMinWidth(width+5);
+        col.setMaxWidth(width+5);
+        
+        // reenable resizing for user
+        col.setMinWidth(0);
+        col.setMaxWidth(999);
+    }
+    
+    private List<TableLine> groupByMethod(List<LogLine> filterResult) {
+        List<TableLine> tableEntries = new ArrayList<>();
+        int firstLine = -1;
+        for (int i = 0; i < filterResult.size(); i++) {
+            LogLine line = filterResult.get(i);
+            
+            if (firstLine < 0)
+                firstLine = line.getLineNumber();
+
+            if (i < filterResult.size() - 1) {
+                LogLine next = filterResult.get(i+1);
+                if (line.getMethod() != next.getMethod()) {
+                    tableEntries.add(new TableLine(line, firstLine));
+                    firstLine = next.getLineNumber();
+                }
+            } else {
+                tableEntries.add(new TableLine(line, firstLine));
+            }
+        }
+        return tableEntries;
+    }
+    
+    private List<TableLine> groupByScope(List<LogLine> filterResult) {
+        List<TableLine> tableEntries = new ArrayList<>();
+        LogLine firstScopeLine = null;
+        for (int i = 0; i < filterResult.size(); i++) {
+            LogLine line = filterResult.get(i);
+            
+            if (firstScopeLine == null)
+                firstScopeLine = line;
+
+            if (i < filterResult.size() - 1) {
+                LogLine next = filterResult.get(i+1);
+                if (line.getScope() != next.getScope()) {
+                    tableEntries.add(new TableLine(firstScopeLine, line.getLineNumber()));
+                    firstScopeLine = next;
+                }
+            } else {
+                tableEntries.add(new TableLine(firstScopeLine, line.getLineNumber()));
+            }
+        }
+        return tableEntries;
+    }
+    
+    private List<TableLine> showAllLines(List<LogLine> filterResult) {
+        List<TableLine> tableEntries = new ArrayList<>();
+        for (LogLine line : filterResult) {
+            tableEntries.add(new TableLine(line));
+        }
+        return tableEntries;
+    }
+    
+    public void loadLogFile() {
+        JFileChooser fc = new JFileChooser();
+        fc.setFileFilter(new javax.swing.filechooser.FileFilter() {
+
+            @Override
+            public boolean accept(File f) {
+                return f.isDirectory() ||
+                       f.getName().toLowerCase().endsWith(".txt") ||
+                       f.getName().toLowerCase().endsWith(".log");
+            }
+
+            @Override
+            public String getDescription() {
+                return "Log files (*.txt, *.log)";
+            }
+        });
+        fc.setCurrentDirectory(new File(NbPreferences.forModule(LogScene.class).get(PREFERENCE_DIR, "~")));
+        fc.setDialogTitle("Load log file");
+
+        if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
+            tryInterruptFilter();
+            
+            final File file = fc.getSelectedFile();
+            
+            NbPreferences.forModule(LogScene.class).put(PREFERENCE_DIR, file.getParent());
+            
+            lblIcon.setIcon(IMGICON_LOAD);
+            logStatus = LogStatus.LOADING;
+            new Thread(new Runnable(){
+
+                @Override
+                public void run() {
+                    try {
+                        logModel = parser.parse(file, new LoadProgressMonitor(lblMessage, "Loading file " + file.getName() + "..."));
+                        lblIcon.setIcon(null);
+                        lblMessage.setText("Current logfile: " + file.getName());
+                        logStatus = LogStatus.ACTIVE;
+                    } catch (IOException ex) {
+                        Exceptions.printStackTrace(ex);
+                    }
+                }
+
+            }).start();
+        }
+    }
+    
+    private class FilterKeyListener extends KeyAdapter {
+        @Override
+        public void keyTyped(KeyEvent e) {
+            tryInterruptFilter();
+            timeSinceLastKeystroke = 0;
+        }
+    }
+    
+    private class FilterFocusListener implements FocusListener {
+        private boolean ignore = false;
+        
+        @Override
+        public void focusGained(FocusEvent fe) {
+            if (!ignore && logStatus == LogStatus.NO_LOG) {
+                ignore = true;
+                loadLogFile();
+            }
+        }
+
+        @Override
+        public void focusLost(FocusEvent fe) {
+            if (fe instanceof CausedFocusEvent) {
+                CausedFocusEvent cfe = (CausedFocusEvent) fe;
+                ignore = ignore && // don't change ignore to true if it is already false
+                         cfe.getCause() == CausedFocusEvent.Cause.ACTIVATION; // ACTIVATION is triggered if the
+                                                                              // FileChooser is opened
+            }
+        }
+        
+    }
+    
+    private class KeystrokeTimer extends TimerTask {
+        @Override
+        public void run() {
+            if (timeSinceLastKeystroke < 0)
+                return;
+            
+            timeSinceLastKeystroke += KEYSTROKE_RATE;
+            
+            if (timeSinceLastKeystroke >= KEYSTROKE_TRESHOLD) {
+                int save = timeSinceLastKeystroke;
+                timeSinceLastKeystroke = -1; // needs to be set to -1 to prevent 
+                                             // multiple parallel filter execution
+                
+                if (!executeFilters())
+                    timeSinceLastKeystroke = save;
+            }
+        }
+    }
+    
+    private class LoadProgressMonitor implements ProgressMonitor {
+        private String staticText;
+        private JLabel lblStatus;
+        
+        public LoadProgressMonitor(JLabel lblStatus, String staticText) {
+            this.lblStatus = lblStatus;
+            this.staticText = staticText;
+            
+            lblStatus.setText(staticText);
+        }
+        
+        @Override
+        public void worked(float percentage) {
+            int perc = Math.round(percentage*100);
+            lblStatus.setText(staticText + " (" + perc + " %)");
+        }
+
+        @Override
+        public void finished() {
+            if (parser.hasErrors()) {
+                if (JOptionPane.showConfirmDialog(LogScene.this, "Parsing log file finished with errors. Show error messages?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) {
+                    List<LogParser.ParseError> errors = parser.getErrors();
+                    ImportLogErrorDialog.showDialog(LogScene.this, errors);
+                }
+            }
+        }
+        
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/actions/ImportLogAction.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene.actions;
+
+import com.oracle.graal.visualizer.logviewer.scene.LogScene;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import org.openide.awt.ActionID;
+import org.openide.awt.ActionReference;
+import org.openide.awt.ActionRegistration;
+
+@ActionID(id = "com.oracle.graal.visualizer.logviewer.scene.actions.ImportLogActions", category = "File")
+@ActionRegistration(displayName = "Import Log", iconBase = "com/oracle/graal/visualizer/logviewer/scene/icons/import_log.png")
+@ActionReference(path = "Menu/File", position = 600)
+public class ImportLogAction implements ActionListener {
+
+    @Override
+    public void actionPerformed(ActionEvent ae) {
+        LogScene.getInstance().loadLogFile();
+    }
+}
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/arrow_down.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/arrow_up.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/bookmark_back.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/bookmark_forward.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/bookmark_list.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/import_log.png has changed
Binary file visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/icons/loading.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/model/LogTableModel.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.table.AbstractTableModel;
+
+public class LogTableModel extends AbstractTableModel {
+    private final static String[] columnNames = {"Line #", "Method", "Scope", "Node", "Log Text"};
+    
+    private List<TableLine> entries = new ArrayList<>();
+    
+    public void setLogEntries(List<TableLine> entries) {
+        this.entries = entries;
+        fireTableDataChanged();
+    }
+    
+    public TableLine getTableLine(int line) {
+        return entries.get(line);
+    }
+    
+    @Override
+    public int getRowCount() {
+        return entries.size();
+    }
+
+    @Override
+    public int getColumnCount() {
+        return columnNames.length;
+    }
+
+    @Override
+    public String getColumnName(int column) {
+        return columnNames[column];
+    }
+
+    @Override
+    public Object getValueAt(int i, int i1) {
+        switch (i1) {
+            case 0:
+                return entries.get(i).getLineNr();
+            case 1:
+                return entries.get(i).getLogLine().getMethod().getName();
+            case 2:
+                return entries.get(i).getLogLine().getScope()!=null?
+                           entries.get(i).getLogLine().getScope().getName():"";
+            case 3:
+                return entries.get(i).getLogLine().getNode()!=null?
+                           entries.get(i).getLogLine().getNode().getName():"";
+            case 4:
+                return entries.get(i).getLogLine().getText();
+        }
+        return null;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/visualizer/LogViewer/src/com/oracle/graal/visualizer/logviewer/scene/model/TableLine.java	Mon Jul 02 18:20:25 2012 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package com.oracle.graal.visualizer.logviewer.scene.model;
+
+import com.oracle.graal.visualizer.logviewer.model.LogLine;
+
+public class TableLine {
+
+    private int lineNr;
+    private LogLine logLine;
+    
+    // display single log line
+    public TableLine(LogLine logLine) {
+        this(logLine, logLine.getLineNumber());
+    }
+    
+    // display line number range (from logLine to lineNr or vice versa)
+    public TableLine(LogLine logLine, int lineNr) {
+        this.logLine = logLine;
+        this.lineNr = lineNr;
+    }
+    
+    public int getFirstLine() {
+        return lineNr < logLine.getLineNumber()?lineNr:logLine.getLineNumber();
+    }
+    
+    public int getLastLine() {
+        return lineNr > logLine.getLineNumber()?lineNr:logLine.getLineNumber();
+    }
+    
+    public String getLineNr() {
+        if (lineNr == logLine.getLineNumber()) {
+            return String.valueOf(lineNr);
+        }
+        return getFirstLine() + "-" + getLastLine();
+    }
+    
+    public LogLine getLogLine() {
+        return logLine;
+    }
+}
--- a/visualizer/nbproject/project.properties	Mon Jul 02 16:53:12 2012 +0200
+++ b/visualizer/nbproject/project.properties	Mon Jul 02 18:20:25 2012 +0200
@@ -1,48 +1,50 @@
-app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif
-app.name=graalvisualizer
-app.title=Graal Visualizer
-branding.token=${app.name}
-modules=\
-    ${project.com.sun.hotspot.igv.graph}:\
-    ${project.com.sun.hotspot.igv.filter}:\
-    ${project.com.sun.hotspot.igv.hierarchicallayout}:\
-    ${project.com.sun.hotspot.igv.layout}:\
-    ${project.com.sun.hotspot.igv.data}:\
-    ${project.com.sun.hotspot.igv.view}:\
-    ${project.com.sun.hotspot.igv.bytecodes}:\
-    ${project.com.sun.hotspot.igv.difference}:\
-    ${project.com.sun.hotspot.igv.settings}:\
-    ${project.com.sun.hotspot.igv.util}:\
-    ${project.com.sun.hotspot.igv.svg}:\
-    ${project.com.sun.hotspot.igv.filterwindow}:\
-    ${project.com.sun.hotspot.igv.graal}:\
-    ${project.at.ssw.visualizer.cfg}:\
-    ${project.org.eclipse.draw2d}:\
-    ${project.com.oracle.graal.visualizer.editor}:\
-    ${project.com.oracle.graal.visualizer.outline}:\
-    ${project.com.oracle.graal.visualizer.snapshots}:\
-    ${project.com.oracle.graal.visualizer.sharedactions}
-project.at.ssw.visualizer.cfg=ControlFlowEditor
-project.com.oracle.graal.visualizer.editor=Editor
-project.com.oracle.graal.visualizer.outline=OutlineView
-project.com.oracle.graal.visualizer.sharedactions=SharedActions
-project.com.oracle.graal.visualizer.snapshots=SnapshotsView
-project.com.sun.hotspot.igv.bytecodes=Bytecodes
-project.com.sun.hotspot.igv.data=Data
-project.com.sun.hotspot.igv.difference=Difference
-project.com.sun.hotspot.igv.filter=Filter
-project.com.sun.hotspot.igv.filterwindow=FilterWindow
-project.com.sun.hotspot.igv.graal=Graal
-project.com.sun.hotspot.igv.graph=Graph
-project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout
-project.com.sun.hotspot.igv.layout=Layout
-project.com.sun.hotspot.igv.settings=Settings
-project.com.sun.hotspot.igv.svg=BatikSVGProxy
-project.com.sun.hotspot.igv.view=View
-project.com.sun.hotspot.igv.util=Util
-
-project.org.eclipse.draw2d=Draw2DLibrary
-# Disable assertions for RequestProcessor to prevent annoying messages in case
-# of multiple SceneAnimator update tasks in the default RequestProcessor.
-run.args.extra = -J-client -J-da:org.openide.util.RequestProcessor
-debug.args.extra = -J-client -J-da:org.openide.util.RequestProcessor
+app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif
+app.name=graalvisualizer
+app.title=Graal Visualizer
+branding.token=${app.name}
+modules=\
+    ${project.com.sun.hotspot.igv.graph}:\
+    ${project.com.sun.hotspot.igv.filter}:\
+    ${project.com.sun.hotspot.igv.hierarchicallayout}:\
+    ${project.com.sun.hotspot.igv.layout}:\
+    ${project.com.sun.hotspot.igv.data}:\
+    ${project.com.sun.hotspot.igv.view}:\
+    ${project.com.sun.hotspot.igv.bytecodes}:\
+    ${project.com.sun.hotspot.igv.difference}:\
+    ${project.com.sun.hotspot.igv.settings}:\
+    ${project.com.sun.hotspot.igv.util}:\
+    ${project.com.sun.hotspot.igv.svg}:\
+    ${project.com.sun.hotspot.igv.filterwindow}:\
+    ${project.com.sun.hotspot.igv.graal}:\
+    ${project.at.ssw.visualizer.cfg}:\
+    ${project.org.eclipse.draw2d}:\
+    ${project.com.oracle.graal.visualizer.editor}:\
+    ${project.com.oracle.graal.visualizer.outline}:\
+    ${project.com.oracle.graal.visualizer.snapshots}:\
+    ${project.com.oracle.graal.visualizer.sharedactions}:\
+    ${project.com.oracle.graal.visualizer.logviewer}
+project.at.ssw.visualizer.cfg=ControlFlowEditor
+project.com.oracle.graal.visualizer.logviewer=LogViewer
+project.com.oracle.graal.visualizer.editor=Editor
+project.com.oracle.graal.visualizer.outline=OutlineView
+project.com.oracle.graal.visualizer.sharedactions=SharedActions
+project.com.oracle.graal.visualizer.snapshots=SnapshotsView
+project.com.sun.hotspot.igv.bytecodes=Bytecodes
+project.com.sun.hotspot.igv.data=Data
+project.com.sun.hotspot.igv.difference=Difference
+project.com.sun.hotspot.igv.filter=Filter
+project.com.sun.hotspot.igv.filterwindow=FilterWindow
+project.com.sun.hotspot.igv.graal=Graal
+project.com.sun.hotspot.igv.graph=Graph
+project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout
+project.com.sun.hotspot.igv.layout=Layout
+project.com.sun.hotspot.igv.settings=Settings
+project.com.sun.hotspot.igv.svg=BatikSVGProxy
+project.com.sun.hotspot.igv.view=View
+project.com.sun.hotspot.igv.util=Util
+
+project.org.eclipse.draw2d=Draw2DLibrary
+# Disable assertions for RequestProcessor to prevent annoying messages in case
+# of multiple SceneAnimator update tasks in the default RequestProcessor.
+run.args.extra = -J-client -J-da:org.openide.util.RequestProcessor
+debug.args.extra = -J-client -J-da:org.openide.util.RequestProcessor