changeset 2842:7596ae867a7b

basic inlining passes all tests, including optimistic inlining
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 01 Jun 2011 16:26:17 +0200
parents 633e66de40fe
children 6960cc79f664
files graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.java graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java graal/GraalCompiler/src/com/sun/c1x/graph/IR.java graal/GraalCompiler/src/com/sun/c1x/ir/LoopBegin.java graal/GraalCompiler/src/com/sun/c1x/ir/LoopEnd.java graal/GraalCompiler/src/com/sun/c1x/ir/Merge.java graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java graal/GraalGraph/src/com/oracle/graal/graph/Graph.java graal/GraalGraph/src/com/oracle/graal/graph/Node.java graal/GraalGraph/src/com/oracle/graal/graph/NodeArray.java
diffstat 15 files changed, 364 insertions(+), 134 deletions(-) [+]
line wrap: on
line diff
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XCompilation.java	Wed Jun 01 16:26:17 2011 +0200
@@ -96,7 +96,7 @@
         this.method = method;
         this.stats = stats == null ? new CiStatistics() : stats;
         this.registerConfig = method == null ? compiler.globalStubRegisterConfig : runtime.getRegisterConfig(method);
-        this.placeholderState = method != null && method.minimalDebugInfo() ? new FrameState(0, 0, 0, 0, graph) : null;
+        this.placeholderState = method != null && method.minimalDebugInfo() ? new FrameState(method, 0, 0, 0, 0, graph) : null;
 
         if (compiler.isObserved()) {
             compiler.fireCompilationStarted(new CompilationEvent(this));
--- a/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/C1XOptions.java	Wed Jun 01 16:26:17 2011 +0200
@@ -90,6 +90,7 @@
     public static boolean TraceRelocation                    = ____;
     public static boolean TraceLIRVisit                      = ____;
     public static boolean TraceAssembler                     = ____;
+    public static boolean TraceInlining                      = ____;
     public static int     TraceBytecodeParserLevel           = 0;
     public static boolean QuietBailout                       = ____;
 
--- a/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/alloc/LinearScan.java	Wed Jun 01 16:26:17 2011 +0200
@@ -1884,7 +1884,7 @@
         }
     }
 
-    CiFrame computeFrameForState(int opId, FrameState state, CiBitMap frameRefMap) {
+    CiFrame computeFrameForState(FrameState state, int opId, CiBitMap frameRefMap) {
         CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()];
         int valueIndex = 0;
 
@@ -1909,8 +1909,11 @@
                 }
             }
         }
-
-        return new CiFrame(null, ir.compilation.method, state.bci, values, state.localsSize(), state.stackSize(), state.locksSize());
+        CiFrame caller = null;
+        if (state.outerFrameState() != null) {
+            caller = computeFrameForState(state.outerFrameState(), opId, frameRefMap);
+        }
+        return new CiFrame(caller, state.method, state.bci, values, state.localsSize(), state.stackSize(), state.locksSize());
     }
 
     private void computeDebugInfo(IntervalWalker iw, LIRInstruction op) {
@@ -1946,7 +1949,7 @@
         if (C1XOptions.TraceLinearScanLevel >= 3) {
             TTY.println("creating debug information at opId %d", opId);
         }
-        return computeFrameForState(opId, state, frameRefMap);
+        return computeFrameForState(state, opId, frameRefMap);
     }
 
     private void assignLocations(List<LIRInstruction> instructions, IntervalWalker iw) {
--- a/graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/gen/LIRGenerator.java	Wed Jun 01 16:26:17 2011 +0200
@@ -300,7 +300,7 @@
         if (Modifier.isSynchronized(compilation.method.accessFlags())) {
             bci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
         }
-        FrameState fs = new FrameState(bci, compilation.method.maxLocals(), 0, 0, compilation.graph);
+        FrameState fs = new FrameState(compilation.method, bci, compilation.method.maxLocals(), 0, 0, compilation.graph);
         for (Node node : compilation.graph.start().usages()) {
             if (node instanceof Local) {
                 Local local = (Local) node;
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/GraphBuilder.java	Wed Jun 01 16:26:17 2011 +0200
@@ -61,24 +61,30 @@
      */
     public static final int TRACELEVEL_STATE = 2;
 
-    private final IR ir;
     private final C1XCompilation compilation;
+    private final CompilerGraph graph;
+
     private final CiStatistics stats;
+    private final RiRuntime runtime;
+    private final RiMethod method;
+    private final RiConstantPool constantPool;
 
     private final BytecodeStream stream;           // the bytecode stream
+    private final LogStream log;
+    private final FrameStateBuilder frameState;          // the current execution state
+
     // bci-to-block mapping
     private Block[] blockFromBci;
     private ArrayList<Block> blockList;
 
-    private Block syncBlock;
+    private int nextBlockNumber;
+
+    private Value methodSynchronizedObject;
     private CiExceptionHandler syncHandler;
 
     private Block unwindBlock;
     private Block returnBlock;
 
-    // the constant pool
-    private final RiConstantPool constantPool;
-
     // the worklist of blocks, sorted by depth first number
     private final PriorityQueue<Block> workList = new PriorityQueue<Block>(10, new Comparator<Block>() {
         public int compare(Block o1, Block o2) {
@@ -86,14 +92,11 @@
         }
     });
 
-    private FrameStateBuilder frameState;          // the current execution state
     private Instruction lastInstr;                 // the last instruction added
 
-    private final LogStream log;
+    private final Set<Block> blocksOnWorklist = new HashSet<Block>();
+    private final Set<Block> blocksVisited = new HashSet<Block>();
 
-    private Value rootMethodSynchronizedObject;
-
-    private final CompilerGraph graph;
 
     /**
      * Creates a new, initialized, {@code GraphBuilder} instance for a given compilation.
@@ -102,15 +105,18 @@
      * @param ir the IR to build the graph into
      * @param graph
      */
-    public GraphBuilder(C1XCompilation compilation, IR ir, CompilerGraph graph) {
+    public GraphBuilder(C1XCompilation compilation, RiMethod method, CompilerGraph graph) {
         this.compilation = compilation;
-        this.ir = ir;
+        this.graph = graph;
+
+        this.runtime = compilation.runtime;
+        this.method = method;
         this.stats = compilation.stats;
-        log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null;
-        stream = new BytecodeStream(compilation.method.code());
-        constantPool = compilation.runtime.getConstantPool(compilation.method);
-        this.graph = graph;
-        this.frameState = new FrameStateBuilder(compilation.method, graph);
+        this.log = C1XOptions.TraceBytecodeParserLevel > 0 ? new LogStream(TTY.out()) : null;
+        this.stream = new BytecodeStream(method.code());
+
+        this.constantPool = runtime.getConstantPool(method);
+        this.frameState = new FrameStateBuilder(method, graph);
     }
 
     /**
@@ -118,20 +124,18 @@
      * @param scope the top IRScope
      */
     public void build() {
-        RiMethod rootMethod = compilation.method;
-
         if (log != null) {
             log.println();
-            log.println("Compiling " + compilation.method);
+            log.println("Compiling " + method);
         }
 
         // 2. compute the block map, setup exception handlers and get the entrypoint(s)
-        BlockMap blockMap = compilation.getBlockMap(rootMethod);
+        BlockMap blockMap = compilation.getBlockMap(method);
 
         blockList = new ArrayList<Block>(blockMap.blocks);
-        blockFromBci = new Block[rootMethod.code().length];
+        blockFromBci = new Block[method.code().length];
         for (int i = 0; i < blockList.size(); i++) {
-            int blockID = ir.nextBlockNumber();
+            int blockID = nextBlockNumber();
             assert blockID == i;
             Block block = blockList.get(i);
             if (block.startBci >= 0) {
@@ -145,15 +149,15 @@
         lastInstr = createTarget(startBlock, frameState);
         graph.start().setStart(lastInstr);
 
-        if (isSynchronized(rootMethod.accessFlags())) {
+        if (isSynchronized(method.accessFlags())) {
             // 4A.1 add a monitor enter to the start block
-            rootMethodSynchronizedObject = synchronizedObject(frameState, compilation.method);
-            genMonitorEnter(rootMethodSynchronizedObject, Instruction.SYNCHRONIZATION_ENTRY_BCI);
+            methodSynchronizedObject = synchronizedObject(frameState, method);
+            genMonitorEnter(methodSynchronizedObject, Instruction.SYNCHRONIZATION_ENTRY_BCI);
             // 4A.2 finish the start block
             finishStartBlock(startBlock);
 
             // 4A.3 setup an exception handler to unlock the root method synchronized object
-            syncHandler = new CiExceptionHandler(0, rootMethod.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null);
+            syncHandler = new CiExceptionHandler(0, method.code().length, Instruction.SYNCHRONIZATION_ENTRY_BCI, 0, null);
         } else {
             // 4B.1 simply finish the start block
             finishStartBlock(startBlock);
@@ -165,6 +169,7 @@
         addToWorkList(blockFromBci[0]);
         iterateAllBlocks();
 
+        // remove Placeholders
         for (Node n : graph.getNodes()) {
             if (n instanceof Placeholder) {
                 Placeholder p = (Placeholder) n;
@@ -176,21 +181,13 @@
             }
         }
 
-        for (Node n : graph.getNodes()) {
-            assert !(n instanceof Placeholder);
-        }
-
-
+        // remove FrameStates
         for (Node n : graph.getNodes()) {
             if (n instanceof FrameState) {
                 boolean delete = false;
                 if (n.usages().size() == 0 && n.predecessors().size() == 0) {
                     delete = true;
                 }
-//                if (n.predecessors().size() == 0 && n.usages().size() == 1 && n.usages().get(0) instanceof BlockBegin) {
-//                    n.usages().get(0).inputs().replace(n, null);
-//                    delete = true;
-//                }
                 if (delete) {
                     n.delete();
                 }
@@ -198,11 +195,16 @@
         }
     }
 
+    private int nextBlockNumber() {
+        stats.blockCount++;
+        return nextBlockNumber++;
+    }
+
     private Block nextBlock(int bci) {
         Block block = new Block();
         block.startBci = bci;
         block.endBci = bci;
-        block.blockID = ir.nextBlockNumber();
+        block.blockID = nextBlockNumber();
         return block;
     }
 
@@ -211,7 +213,7 @@
             unwindBlock = new Block();
             unwindBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
             unwindBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
-            unwindBlock.blockID = ir.nextBlockNumber();
+            unwindBlock.blockID = nextBlockNumber();
             addToWorkList(unwindBlock);
         }
         return unwindBlock;
@@ -222,15 +224,12 @@
             returnBlock = new Block();
             returnBlock.startBci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
             returnBlock.endBci = Instruction.SYNCHRONIZATION_ENTRY_BCI;
-            returnBlock.blockID = ir.nextBlockNumber();
+            returnBlock.blockID = nextBlockNumber();
             addToWorkList(returnBlock);
         }
         return returnBlock;
     }
 
-
-    private Set<Block> blocksOnWorklist = new HashSet<Block>();
-
     private void markOnWorkList(Block block) {
         blocksOnWorklist.add(block);
     }
@@ -239,8 +238,6 @@
         return blocksOnWorklist.contains(block);
     }
 
-    private Set<Block> blocksVisited = new HashSet<Block>();
-
     private void markVisited(Block block) {
         blocksVisited.add(block);
     }
@@ -328,10 +325,6 @@
         }
     }
 
-    public RiMethod method() {
-        return compilation.method;
-    }
-
     public BytecodeStream stream() {
         return stream;
     }
@@ -360,7 +353,7 @@
         assert bci == Instruction.SYNCHRONIZATION_ENTRY_BCI || bci == bci() : "invalid bci";
 
         RiExceptionHandler firstHandler = null;
-        RiExceptionHandler[] exceptionHandlers = compilation.method.exceptionHandlers();
+        RiExceptionHandler[] exceptionHandlers = method.exceptionHandlers();
         // join with all potential exception handlers
         if (exceptionHandlers != null) {
             for (RiExceptionHandler handler : exceptionHandlers) {
@@ -422,7 +415,7 @@
     }
 
     private void genLoadConstant(int cpi) {
-        Object con = constantPool().lookupConstant(cpi);
+        Object con = constantPool.lookupConstant(cpi);
 
         if (con instanceof RiType) {
             // this is a load of class constant which might be unresolved
@@ -550,7 +543,7 @@
     private void genArithmeticOp(CiKind result, int opcode, CiKind x, CiKind y, boolean canTrap) {
         Value yValue = frameState.pop(y);
         Value xValue = frameState.pop(x);
-        Value result1 = append(new ArithmeticOp(opcode, result, xValue, yValue, isStrict(method().accessFlags()), canTrap, graph));
+        Value result1 = append(new ArithmeticOp(opcode, result, xValue, yValue, isStrict(method.accessFlags()), canTrap, graph));
         frameState.push(result, result1);
     }
 
@@ -589,7 +582,7 @@
         int delta = stream().readIncrement();
         Value x = frameState.localAt(index);
         Value y = append(Constant.forInt(delta, graph));
-        frameState.storeLocal(index, append(new ArithmeticOp(IADD, CiKind.Int, x, y, isStrict(method().accessFlags()), false, graph)));
+        frameState.storeLocal(index, append(new ArithmeticOp(IADD, CiKind.Int, x, y, isStrict(method.accessFlags()), false, graph)));
     }
 
     private void genGoto(int fromBCI, int toBCI) {
@@ -641,7 +634,7 @@
 
     private void genCheckCast() {
         int cpi = stream().readCPI();
-        RiType type = constantPool().lookupType(cpi, CHECKCAST);
+        RiType type = constantPool.lookupType(cpi, CHECKCAST);
         boolean isInitialized = type.isResolved();
         Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi);
         Value object = frameState.apop();
@@ -654,7 +647,7 @@
 
     private void genInstanceOf() {
         int cpi = stream().readCPI();
-        RiType type = constantPool().lookupType(cpi, INSTANCEOF);
+        RiType type = constantPool.lookupType(cpi, INSTANCEOF);
         boolean isInitialized = type.isResolved();
         Value typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, isInitialized, cpi);
         Value object = frameState.apop();
@@ -666,9 +659,9 @@
     }
 
     void genNewInstance(int cpi) {
-        RiType type = constantPool().lookupType(cpi, NEW);
+        RiType type = constantPool.lookupType(cpi, NEW);
         if (type.isResolved()) {
-            NewInstance n = new NewInstance(type, cpi, constantPool(), graph);
+            NewInstance n = new NewInstance(type, cpi, constantPool, graph);
             frameState.apush(append(n));
         } else {
             append(new Deoptimize(graph));
@@ -678,13 +671,13 @@
 
     private void genNewTypeArray(int typeCode) {
         CiKind kind = CiKind.fromArrayTypeCode(typeCode);
-        RiType elementType = compilation.runtime.asRiType(kind);
+        RiType elementType = runtime.asRiType(kind);
         NewTypeArray nta = new NewTypeArray(frameState.ipop(), elementType, graph);
         frameState.apush(append(nta));
     }
 
     private void genNewObjectArray(int cpi) {
-        RiType type = constantPool().lookupType(cpi, ANEWARRAY);
+        RiType type = constantPool.lookupType(cpi, ANEWARRAY);
         Value length = frameState.ipop();
         if (type.isResolved()) {
             NewArray n = new NewObjectArray(type, length, graph);
@@ -697,14 +690,14 @@
     }
 
     private void genNewMultiArray(int cpi) {
-        RiType type = constantPool().lookupType(cpi, MULTIANEWARRAY);
+        RiType type = constantPool.lookupType(cpi, MULTIANEWARRAY);
         int rank = stream().readUByte(bci() + 3);
         Value[] dims = new Value[rank];
         for (int i = rank - 1; i >= 0; i--) {
             dims[i] = frameState.ipop();
         }
         if (type.isResolved()) {
-            NewArray n = new NewMultiArray(type, dims, cpi, constantPool(), graph);
+            NewArray n = new NewMultiArray(type, dims, cpi, constantPool, graph);
             frameState.apush(append(n));
         } else {
             append(new Deoptimize(graph));
@@ -853,7 +846,7 @@
 
     private void appendInvoke(int opcode, RiMethod target, Value[] args, int cpi, RiConstantPool constantPool) {
         CiKind resultType = returnKind(target);
-        Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(compilation.method.holder()), graph);
+        Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), graph);
         Value result = appendWithBCI(invoke);
         invoke.setExceptionEdge(handleException(null, bci()));
         frameState.pushReturn(resultType, result);
@@ -865,7 +858,7 @@
             exact = receiver.exactType();
             if (exact == null) {
                 if (receiver.isConstant()) {
-                    exact = compilation.runtime.getTypeOf(receiver.asConstant());
+                    exact = runtime.getTypeOf(receiver.asConstant());
                 }
                 if (exact == null) {
                     RiType declared = receiver.declaredType();
@@ -886,7 +879,7 @@
         }
         if (exactType == null && receiver instanceof Local && ((Local) receiver).index() == 0) {
             // the exact type isn't known, but the receiver is parameter 0 => use holder
-            receiverType = compilation.method.holder();
+            receiverType = method.holder();
             exactType = receiverType.exactType();
         }
         boolean needsCheck = true;
@@ -926,13 +919,13 @@
     private void genMonitorEnter(Value x, int bci) {
         int lockNumber = frameState.locksSize();
         MonitorAddress lockAddress = null;
-        if (compilation.runtime.sizeOfBasicObjectLock() != 0) {
+        if (runtime.sizeOfBasicObjectLock() != 0) {
             lockAddress = new MonitorAddress(lockNumber, graph);
             append(lockAddress);
         }
         MonitorEnter monitorEnter = new MonitorEnter(x, lockAddress, lockNumber, graph);
         appendWithBCI(monitorEnter);
-        frameState.lock(ir, x, lockNumber + 1);
+        frameState.lock(x);
         if (bci == Instruction.SYNCHRONIZATION_ENTRY_BCI) {
             monitorEnter.setStateAfter(frameState.create(0));
         }
@@ -944,7 +937,7 @@
             throw new CiBailout("monitor stack underflow");
         }
         MonitorAddress lockAddress = null;
-        if (compilation.runtime.sizeOfBasicObjectLock() != 0) {
+        if (runtime.sizeOfBasicObjectLock() != 0) {
             lockAddress = new MonitorAddress(lockNumber, graph);
             append(lockAddress);
         }
@@ -1130,22 +1123,22 @@
     }
 
     private void createUnwindBlock(Block block) {
-        if (Modifier.isSynchronized(method().accessFlags())) {
-            genMonitorExit(rootMethodSynchronizedObject);
+        if (Modifier.isSynchronized(method.accessFlags())) {
+            genMonitorExit(methodSynchronizedObject);
         }
         append(graph.createUnwind(frameState.apop()));
     }
 
     private void createReturnBlock(Block block) {
-        if (method().isConstructor() && method().holder().superType() == null) {
+        if (method.isConstructor() && method.holder().superType() == null) {
             callRegisterFinalizer();
         }
-        CiKind returnKind = method().signature().returnKind().stackKind();
+        CiKind returnKind = method.signature().returnKind().stackKind();
         Value x = returnKind == CiKind.Void ? null : frameState.pop(returnKind);
         assert frameState.stackSize() == 0;
 
-        if (Modifier.isSynchronized(method().accessFlags())) {
-            genMonitorExit(rootMethodSynchronizedObject);
+        if (Modifier.isSynchronized(method.accessFlags())) {
+            genMonitorExit(methodSynchronizedObject);
         }
         append(graph.createReturn(x));
     }
@@ -1218,7 +1211,7 @@
 
     private void traceState() {
         if (C1XOptions.TraceBytecodeParserLevel >= TRACELEVEL_STATE && !TTY.isSuppressed()) {
-            log.println(String.format("|   state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method()));
+            log.println(String.format("|   state [nr locals = %d, stack depth = %d, method = %s]", frameState.localsSize(), frameState.stackSize(), method));
             for (int i = 0; i < frameState.localsSize(); ++i) {
                 Value value = frameState.localAt(i);
                 log.println(String.format("|   local[%d] = %-8s : %s", i, value == null ? "bogus" : value.kind.javaName, value));
@@ -1417,14 +1410,14 @@
             case DRETURN        : genReturn(frameState.dpop()); break;
             case ARETURN        : genReturn(frameState.apop()); break;
             case RETURN         : genReturn(null  ); break;
-            case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(cpi, constantPool().lookupField(cpi, opcode)); break;
-            case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(cpi, constantPool().lookupField(cpi, opcode)); break;
-            case GETFIELD       : cpi = stream.readCPI(); genGetField(cpi, constantPool().lookupField(cpi, opcode)); break;
-            case PUTFIELD       : cpi = stream.readCPI(); genPutField(cpi, constantPool().lookupField(cpi, opcode)); break;
-            case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(constantPool().lookupMethod(cpi, opcode), cpi, constantPool()); break;
-            case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(constantPool().lookupMethod(cpi, opcode), null, cpi, constantPool()); break;
-            case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(constantPool().lookupMethod(cpi, opcode), cpi, constantPool()); break;
-            case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(constantPool().lookupMethod(cpi, opcode), cpi, constantPool()); break;
+            case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(cpi, constantPool.lookupField(cpi, opcode)); break;
+            case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(cpi, constantPool.lookupField(cpi, opcode)); break;
+            case GETFIELD       : cpi = stream.readCPI(); genGetField(cpi, constantPool.lookupField(cpi, opcode)); break;
+            case PUTFIELD       : cpi = stream.readCPI(); genPutField(cpi, constantPool.lookupField(cpi, opcode)); break;
+            case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break;
+            case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(constantPool.lookupMethod(cpi, opcode), null, cpi, constantPool); break;
+            case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break;
+            case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(constantPool.lookupMethod(cpi, opcode), cpi, constantPool); break;
             case NEW            : genNewInstance(stream.readCPI()); break;
             case NEWARRAY       : genNewTypeArray(stream.readLocalIndex()); break;
             case ANEWARRAY      : genNewObjectArray(stream.readCPI()); break;
@@ -1468,10 +1461,6 @@
         frameState.ipush(append(new ArrayLength(frameState.apop(), graph)));
     }
 
-    private RiConstantPool constantPool() {
-        return constantPool;
-    }
-
     /**
      * Adds a block to the worklist, if it is not already in the worklist.
      * This method will keep the worklist topologically stored (i.e. the lower
--- a/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/graph/IR.java	Wed Jun 01 16:26:17 2011 +0200
@@ -22,6 +22,7 @@
  */
 package com.sun.c1x.graph;
 
+import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.graal.graph.*;
@@ -33,6 +34,8 @@
 import com.sun.c1x.lir.*;
 import com.sun.c1x.observer.*;
 import com.sun.c1x.value.*;
+import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
 
 /**
  * This class implements the overall container for the HIR (high-level IR) graph
@@ -161,12 +164,227 @@
 
     private void buildGraph() {
         // Graph builder must set the startBlock and the osrEntryBlock
-        new GraphBuilder(compilation, this, compilation.graph).build();
+        new GraphBuilder(compilation, compilation.method, compilation.graph).build();
 
         verifyAndPrint("After graph building");
 
+        List<Invoke> trivialInline = new ArrayList<Invoke>();
+        List<Invoke> deoptInline = new ArrayList<Invoke>();
+        List<RiMethod> deoptMethods = new ArrayList<RiMethod>();
+        for (Node node : compilation.graph.getNodes()) {
+            if (node instanceof Invoke) {
+                Invoke invoke = (Invoke) node;
+                RiMethod target = invoke.target;
+                if (target.isResolved() && !Modifier.isNative(target.accessFlags())) {
+                    if (target.canBeStaticallyBound()) {
+                        trivialInline.add(invoke);
+                    } else {
+                        RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target);
+                        if (concrete != null) {
+                            deoptInline.add(invoke);
+                            deoptMethods.add(concrete);
+                        }
+                    }
+                }
+            }
+        }
+
+        int allowedInlinings = 50;
+        for (Invoke invoke : trivialInline) {
+            if (inlineMethod(invoke, invoke.target)) {
+                if (--allowedInlinings <= 0) {
+                    break;
+                }
+            }
+        }
+
+        for (int i = 0; i < deoptInline.size(); i++) {
+            Invoke invoke = deoptInline.get(i);
+            RiMethod method = deoptMethods.get(i);
+            if (inlineMethod(invoke, method)) {
+                if (C1XOptions.TraceInlining) {
+                    System.out.println("registering concrete method assumption...");
+                }
+                compilation.assumptions.recordConcreteMethod(invoke.target, method);
+                if (--allowedInlinings <= 0) {
+                    break;
+                }
+            }
+        }
+
         if (C1XOptions.PrintCompilation) {
-            TTY.print(String.format("%3d blocks | ", this.numberOfBlocks()));
+            TTY.print(String.format("%3d blocks | ", compilation.stats.blockCount));
+        }
+    }
+
+    private boolean inlineMethod(Invoke invoke, RiMethod method) {
+        String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)";
+
+        if (method.code().length > 50) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of code size");
+            }
+            return false;
+        }
+
+        Instruction exceptionEdge = invoke.exceptionEdge();
+        if (exceptionEdge != null) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of exceptionEdge");
+            }
+            return false;
+        }
+        if (!method.holder().isInitialized()) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of non-initialized class");
+            }
+            return false;
+        }
+
+        if (C1XOptions.TraceInlining) {
+            System.out.println("building graph: " + name);
+        }
+        CompilerGraph graph = new CompilerGraph();
+        new GraphBuilder(compilation, method, graph).build();
+
+        boolean withReceiver = !Modifier.isStatic(method.accessFlags());
+
+        int argumentCount = method.signature().argumentCount(false);
+        Value[] parameters = new Value[argumentCount + (withReceiver ? 1 : 0)];
+        int slot = withReceiver ? 1 : 0;
+        int param = withReceiver ? 1 : 0;
+        for (int i = 0; i < argumentCount; i++) {
+            parameters[param++] = invoke.argument(slot);
+            slot += method.signature().argumentKindAt(i).sizeInSlots();
+        }
+        if (withReceiver) {
+            parameters[0] = invoke.argument(0);
+        }
+
+        HashMap<Node, Node> replacements = new HashMap<Node, Node>();
+        ArrayList<Node> nodes = new ArrayList<Node>();
+        ArrayList<Node> frameStates = new ArrayList<Node>();
+        Return returnNode = null;
+        Unwind unwindNode = null;
+        StartNode startNode = null;
+        boolean invokes = false;
+        for (Node node : graph.getNodes()) {
+            if (node != null) {
+                if (node instanceof StartNode) {
+                    startNode = (StartNode) node;
+                } else if (node instanceof Local) {
+                    replacements.put(node, parameters[((Local) node).index()]);
+                } else {
+                    nodes.add(node);
+                    if (node instanceof Return) {
+                        returnNode = (Return) node;
+                    } else if (node instanceof Unwind) {
+                        unwindNode = (Unwind) node;
+                    } else if (node instanceof FrameState) {
+                        frameStates.add(node);
+                    }
+                }
+            }
+        }
+        if (unwindNode != null) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of unwind node");
+            }
+            return false;
+        }
+        if (invokes) {
+            if (C1XOptions.TraceInlining) {
+                System.out.println("not inlining " + name + " because of invokes");
+            }
+            return false;
+        }
+
+        if (C1XOptions.TraceInlining) {
+            System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes");
+        }
+
+        Instruction pred;
+        if (withReceiver) {
+            pred = new NullCheck(parameters[0], compilation.graph);
+        } else {
+            pred = new Merge(compilation.graph);
+        }
+        assert invoke.predecessors().size() == 1;
+        invoke.predecessors().get(0).successors().replace(invoke, pred);
+        replacements.put(startNode, pred);
+
+        Map<Node, Node> duplicates = compilation.graph.addDuplicate(nodes, replacements);
+
+        if (returnNode != null) {
+            List<Node> usages = new ArrayList<Node>(invoke.usages());
+            for (Node usage : usages) {
+                if (returnNode.result() instanceof Local) {
+                    usage.inputs().replace(invoke, replacements.get(returnNode.result()));
+                } else {
+                    usage.inputs().replace(invoke, duplicates.get(returnNode.result()));
+                }
+            }
+            Node returnDuplicate = duplicates.get(returnNode);
+            returnDuplicate.inputs().clearAll();
+
+            assert returnDuplicate.predecessors().size() == 1;
+            Node returnPred = returnDuplicate.predecessors().get(0);
+            int index = returnDuplicate.predecessorsIndex().get(0);
+            returnPred.successors().setAndClear(index, invoke, 0);
+
+            returnDuplicate.delete();
+        }
+        FrameState stateAfter = invoke.stateAfter();
+        if (frameStates.size() > 0) {
+            FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind);
+            for (Node frameState : frameStates) {
+                ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState);
+            }
+        }
+
+        invoke.successors().clearAll();
+        invoke.inputs().clearAll();
+        invoke.delete();
+
+        stateAfter.delete();
+
+        deleteUnused(exceptionEdge);
+
+        verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false));
+        return true;
+    }
+
+    private void deleteUnused(Node node) {
+        if (node != null && node.predecessors().size() == 0) {
+            if (node instanceof ExceptionObject) {
+                Node successor = node.successors().get(0);
+                node.successors().clearAll();
+                if (successor instanceof ExceptionDispatch) {
+                    ExceptionDispatch dispatch = (ExceptionDispatch) successor;
+                    Node succ1 = dispatch.catchSuccessor();
+                    Node succ2 = dispatch.otherSuccessor();
+                    if (succ1 instanceof Merge) {
+                        ((Merge) succ1).removePhiPredecessor(dispatch);
+                    }
+                    if (succ2 instanceof Merge) {
+                        ((Merge) succ2).removePhiPredecessor(dispatch);
+                    }
+                    dispatch.successors().clearAll();
+                    deleteUnused(succ1);
+                    deleteUnused(succ2);
+                    dispatch.delete();
+                } else {
+                    assert successor instanceof Merge;
+                    System.out.println("succ: " + successor.successors().get(0));
+                    Node next = successor.successors().get(0);
+                    successor.successors().clearAll();
+                    deleteUnused(next);
+                    successor.delete();
+                }
+                node.delete();
+            } else if (node instanceof Unwind) {
+                node.delete();
+            }
         }
     }
 
@@ -202,15 +420,6 @@
         }
     }
 
-
-    public int nextBlockNumber() {
-        return compilation.stats.blockCount++;
-    }
-
-    public int numberOfBlocks() {
-        return compilation.stats.blockCount;
-    }
-
     public int numLoops() {
         return compilation.stats.loopCount;
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/LoopBegin.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/LoopBegin.java	Wed Jun 01 16:26:17 2011 +0200
@@ -58,6 +58,11 @@
     }
 
     @Override
+    public String shortName() {
+        return "LoopBegin";
+    }
+
+    @Override
     public Node copy(Graph into) {
         LoopBegin x = new LoopBegin(into);
         x.setNonNull(isNonNull());
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/LoopEnd.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/LoopEnd.java	Wed Jun 01 16:26:17 2011 +0200
@@ -69,6 +69,11 @@
     }
 
     @Override
+    public String shortName() {
+        return "LoopEnd";
+    }
+
+    @Override
     public Node copy(Graph into) {
         LoopEnd x = new LoopEnd(into);
         x.setNonNull(isNonNull());
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Merge.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Merge.java	Wed Jun 01 16:26:17 2011 +0200
@@ -267,4 +267,17 @@
         x.setNonNull(isNonNull());
         return x;
     }
+
+    public void removePhiPredecessor(ExceptionDispatch successor) {
+        int predIndex = predecessors().indexOf(successor);
+        assert predIndex != -1;
+
+        for (Node usage : usages()) {
+            if (usage instanceof Phi) {
+                Phi phi = (Phi) usage;
+                assert phi.valueCount() == predecessors().size();
+                phi.removeInput(predIndex + 1);
+            }
+        }
+    }
 }
--- a/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/ir/Phi.java	Wed Jun 01 16:26:17 2011 +0200
@@ -131,15 +131,11 @@
     @Override
     public String shortName() {
         StringBuilder str = new StringBuilder();
-        for (int i = 1; i < inputs().size(); ++i) {
-            if (i != 1) {
+        for (int i = 0; i < valueCount(); ++i) {
+            if (i != 0) {
                 str.append(' ');
             }
-            if (inputs().get(i) != null) {
-                str.append(inputs().get(i).id());
-            } else {
-                str.append("-");
-            }
+            str.append(valueAt(i) == null ? "-" : valueAt(i).id());
         }
         return "Phi: (" + str + ")";
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameState.java	Wed Jun 01 16:26:17 2011 +0200
@@ -31,6 +31,7 @@
 import com.sun.c1x.debug.*;
 import com.sun.c1x.ir.*;
 import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
 
 /**
  * The {@code FrameState} class encapsulates the frame state (i.e. local variables and
@@ -60,13 +61,12 @@
         return super.successorCount() + SUCCESSOR_COUNT;
     }
 
-    public Value outerFrameState() {
-        return (Value) inputs().get(super.inputCount() + INPUT_OUTER_FRAME_STATE);
+    public FrameState outerFrameState() {
+        return (FrameState) inputs().get(super.inputCount() + INPUT_OUTER_FRAME_STATE);
     }
 
-    public Value setOuterFrameState(Value n) {
-        assert n == null || n.kind == CiKind.Object;
-        return (Value) inputs().set(super.inputCount() + INPUT_OUTER_FRAME_STATE, n);
+    public FrameState setOuterFrameState(FrameState n) {
+        return (FrameState) inputs().set(super.inputCount() + INPUT_OUTER_FRAME_STATE, n);
     }
 
     @Override
@@ -80,6 +80,8 @@
      */
     public final int bci;
 
+    public final RiMethod method;
+
     /**
      * Creates a {@code FrameState} for the given scope and maximum number of stack and local variables.
      *
@@ -88,8 +90,9 @@
      * @param stackSize size of the stack
      * @param lockSize number of locks
      */
-    public FrameState(int bci, int localsSize, int stackSize, int locksSize, Graph graph) {
+    public FrameState(RiMethod method, int bci, int localsSize, int stackSize, int locksSize, Graph graph) {
         super(CiKind.Illegal, localsSize + stackSize + locksSize + INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        this.method = method;
         this.bci = bci;
         this.localsSize = localsSize;
         this.stackSize = stackSize;
@@ -98,8 +101,8 @@
         C1XMetrics.FrameStateValuesCreated += localsSize + stackSize + locksSize;
     }
 
-    FrameState(int bci, Value[] locals, Value[] stack, int stackSize, ArrayList<Value> locks, Graph graph) {
-        this(bci, locals.length, stackSize, locks.size(), graph);
+    FrameState(RiMethod method, int bci, Value[] locals, Value[] stack, int stackSize, ArrayList<Value> locks, Graph graph) {
+        this(method, bci, locals.length, stackSize, locks.size(), graph);
         for (int i = 0; i < locals.length; i++) {
             setValueAt(i, locals[i]);
         }
@@ -125,7 +128,7 @@
      */
     @Override
     public FrameState duplicateWithEmptyStack(int bci) {
-        FrameState other = new FrameState(bci, localsSize, 0, locksSize(), graph());
+        FrameState other = new FrameState(method, bci, localsSize, 0, locksSize(), graph());
         for (int i = 0; i < localsSize; i++) {
             other.setValueAt(i, localAt(i));
         }
@@ -144,7 +147,7 @@
     public FrameState duplicateModified(int bci, CiKind popKind, Value... pushedValues) {
         int popSlots = popKind.sizeInSlots();
         int pushSlots = pushedValues.length;
-        FrameState other = new FrameState(bci, localsSize, stackSize - popSlots + pushSlots, locksSize(), graph());
+        FrameState other = new FrameState(method, bci, localsSize, stackSize - popSlots + pushSlots, locksSize(), graph());
         for (int i = 0; i < localsSize; i++) {
             other.setValueAt(i, localAt(i));
         }
@@ -403,11 +406,9 @@
     }
 
     public Merge block() {
-        if (usages().size() > 0) {
-            assert usages().size() == 1;
-            Node node = usages().get(0);
-            if (node instanceof Merge) {
-                return (Merge) node;
+        for (Node usage : usages()) {
+            if (usage instanceof Merge) {
+                return (Merge) usage;
             }
         }
         return null;
@@ -453,6 +454,9 @@
                 proc.doValue(value);
             }
         }
+        if (outerFrameState() != null) {
+            outerFrameState().forEachLiveStateValue(proc);
+        }
     }
 
     @Override
@@ -487,12 +491,12 @@
 
     @Override
     public FrameState copy() {
-        return new FrameState(bci, localsSize, stackSize, locksSize, graph());
+        return new FrameState(method, bci, localsSize, stackSize, locksSize, graph());
     }
 
 
     private FrameState copy(int newBci) {
-        return new FrameState(newBci, localsSize, stackSize, locksSize, graph());
+        return new FrameState(method, newBci, localsSize, stackSize, locksSize, graph());
     }
 
     @Override
@@ -506,7 +510,7 @@
 
     @Override
     public Node copy(Graph into) {
-        FrameState x = new FrameState(bci, localsSize, stackSize, locksSize, into);
+        FrameState x = new FrameState(method, bci, localsSize, stackSize, locksSize, into);
         x.setNonNull(isNonNull());
         return x;
     }
--- a/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalCompiler/src/com/sun/c1x/value/FrameStateBuilder.java	Wed Jun 01 16:26:17 2011 +0200
@@ -28,7 +28,6 @@
 import java.util.*;
 
 import com.oracle.graal.graph.*;
-import com.sun.c1x.graph.*;
 import com.sun.c1x.ir.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
@@ -44,7 +43,10 @@
 
     private int stackIndex;
 
+    private final RiMethod method;
+
     public FrameStateBuilder(RiMethod method, Graph graph) {
+        this.method = method;
         this.graph = graph;
         this.locals = new Value[method.maxLocals()];
         this.stack = new Value[method.maxStackSize()];
@@ -97,12 +99,12 @@
     }
 
     public FrameState create(int bci) {
-        return new FrameState(bci, locals, stack, stackIndex, locks, graph);
+        return new FrameState(method, bci, locals, stack, stackIndex, locks, graph);
     }
 
     @Override
     public FrameState duplicateWithEmptyStack(int bci) {
-        FrameState frameState = new FrameState(bci, locals, new Value[0], 0, locks, graph);
+        FrameState frameState = new FrameState(method, bci, locals, new Value[0], 0, locks, graph);
         frameState.setOuterFrameState(outerFrameState());
         return frameState;
     }
@@ -361,7 +363,7 @@
      * @param scope the IRScope in which this locking operation occurs
      * @param obj the object being locked
      */
-    public void lock(IR ir, Value obj, int totalNumberOfLocks) {
+    public void lock(Value obj) {
         locks.add(obj);
     }
 
@@ -498,7 +500,7 @@
     }
 
     @Override
-    public Value outerFrameState() {
+    public FrameState outerFrameState() {
         return null;
     }
 }
--- a/graal/GraalGraph/src/com/oracle/graal/graph/Graph.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalGraph/src/com/oracle/graal/graph/Graph.java	Wed Jun 01 16:26:17 2011 +0200
@@ -67,7 +67,7 @@
         return new NodeMap<T>(this);
     }
 
-    public void addDuplicate(Collection<Node> nodes, Map<Node, Node> replacements) {
+    public Map<Node, Node> addDuplicate(Collection<Node> nodes, Map<Node, Node> replacements) {
         Map<Node, Node> newNodes = new HashMap<Node, Node>();
         // create node duplicates
         for (Node node : nodes) {
@@ -125,5 +125,6 @@
                 }
             }
         }
+        return newNodes;
     }
 }
--- a/graal/GraalGraph/src/com/oracle/graal/graph/Node.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalGraph/src/com/oracle/graal/graph/Node.java	Wed Jun 01 16:26:17 2011 +0200
@@ -118,7 +118,7 @@
 
     public void delete() {
         assert !isDeleted();
-        assert usages.size() == 0 && predecessors.size() == 0;
+        assert usages.size() == 0 && predecessors.size() == 0 : "usages: " + usages.size() + ", predecessors: " + predecessors().size();
         assert predecessorsIndex.size() == 0;
         for (int i = 0; i < inputs.size(); ++i) {
             inputs.set(i, Null);
--- a/graal/GraalGraph/src/com/oracle/graal/graph/NodeArray.java	Tue May 31 16:54:15 2011 +0200
+++ b/graal/GraalGraph/src/com/oracle/graal/graph/NodeArray.java	Wed Jun 01 16:26:17 2011 +0200
@@ -127,8 +127,10 @@
             if (value.predecessors.get(i) == clearedNode && value.predecessorsIndex.get(i) == clearedIndex) {
                 value.predecessors.set(i, self());
                 value.predecessorsIndex.set(i, index);
+                return;
             }
         }
+        assert false;
     }
 
     public int size() {