Mercurial > hg > graal-jvmci-8
diff graal/GraalCompiler/src/com/sun/c1x/graph/Inlining.java @ 2868:6d24c27902a2
turned inlining into a phase, some node cloning fixes, added NodeWorklist
author | Lukas Stadler <lukas.stadler@jku.at> |
---|---|
date | Tue, 07 Jun 2011 19:19:14 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/GraalCompiler/src/com/sun/c1x/graph/Inlining.java Tue Jun 07 19:19:14 2011 +0200 @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.c1x.graph; + +import java.lang.reflect.*; +import java.util.*; + +import com.oracle.graal.graph.*; +import com.sun.c1x.*; +import com.sun.c1x.ir.*; +import com.sun.c1x.value.*; +import com.sun.cri.ci.*; +import com.sun.cri.ri.*; + + +public class Inlining extends Phase { + + private final C1XCompilation compilation; + private final IR ir; + + private final Queue<Invoke> invokes = new ArrayDeque<Invoke>(); + private final Queue<RiMethod> methods = new ArrayDeque<RiMethod>(); + private int inliningSize; + + public Inlining(C1XCompilation compilation, IR ir) { + this.compilation = compilation; + this.ir = ir; + } + + private void addToQueue(Invoke invoke, RiMethod method) { + invokes.add(invoke); + methods.add(method); + inliningSize += method.code().length; + } + + @Override + protected void run(Graph graph) { + if (!C1XOptions.Inline) { + return; + } + + inliningSize = compilation.method.code().length; + int iterations = C1XOptions.MaximumRecursiveInlineLevel; + do { + for (Node node : graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + RiMethod target = invoke.target; + if (!checkInliningConditions(invoke) || !target.isResolved() || Modifier.isNative(target.accessFlags())) { + continue; + } + if (target.canBeStaticallyBound()) { + if (checkInliningConditions(invoke.target)) { + addToQueue(invoke, invoke.target); + } + } else { + RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target); + if (concrete != null && concrete.isResolved() && !Modifier.isNative(concrete.accessFlags())) { + if (checkInliningConditions(concrete)) { + if (C1XOptions.TraceInlining) { + System.out.println("registering concrete method assumption..."); + } + compilation.assumptions.recordConcreteMethod(invoke.target, concrete); + addToQueue(invoke, concrete); + } + } + } + if (inliningSize > C1XOptions.MaximumInstructionCount) { + break; + } + } + } + + assert invokes.size() == methods.size(); + if (invokes.isEmpty()) { + break; + } + + Invoke invoke; + while ((invoke = invokes.poll()) != null) { + RiMethod method = methods.remove(); + inlineMethod(invoke, method); + } + DeadCodeElimination dce = new DeadCodeElimination(); + dce.apply(graph); + if (dce.deletedNodeCount > 0) { + ir.verifyAndPrint("After dead code elimination"); + } + ir.verifyAndPrint("After inlining iteration"); + + if (inliningSize > C1XOptions.MaximumInstructionCount) { + if (C1XOptions.TraceInlining) { + System.out.println("inlining stopped: MaximumInstructionCount reached"); + } + break; + } + } while(--iterations > 0); + } + + private boolean checkInliningConditions(Invoke invoke) { + String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", invoke.target, false); + if (invoke.predecessors().size() == 0) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because the invoke is dead code"); + } + return false; + } + return true; + } + + private boolean checkInliningConditions(RiMethod method) { + String name = null; + if (C1XOptions.TraceInlining) { + name = CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; + } + if (method.code().length > C1XOptions.MaximumInlineSize) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of code size"); + } + return false; + } + if (!method.holder().isInitialized()) { + if (C1XOptions.TraceInlining) { + System.out.println("not inlining " + name + " because of non-initialized class"); + } + return false; + } + return true; + } + + private void inlineMethod(Invoke invoke, RiMethod method) { + String name = invoke.id() + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.code().length + " bytes)"; + FrameState stateAfter = invoke.stateAfter(); + Instruction exceptionEdge = invoke.exceptionEdge(); + + if (C1XOptions.TraceInlining) { + System.out.printf("Building graph for %s, locals: %d, stack: %d\n", name, method.maxLocals(), method.maxStackSize()); + } + + CompilerGraph graph = new CompilerGraph(); + new GraphBuilder(compilation, method, graph).build(true); + + 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 = graph.start(); + for (Node node : graph.getNodes()) { + if (node != null) { + if (node instanceof StartNode) { + assert 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 (C1XOptions.TraceInlining) { + ir.printGraph("Subgraph " + CiUtil.format("%H.%n(%p):%r", method, false), graph); + System.out.println("inlining " + name + ": " + frameStates.size() + " frame states, " + nodes.size() + " nodes"); + } + + assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size(); + Instruction pred; + if (withReceiver) { + pred = new NullCheck(parameters[0], compilation.graph); + } else { + pred = new Merge(compilation.graph); + } + 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(); + } + +// if (invoke.next() instanceof Merge) { +// ((Merge) invoke.next()).removePhiPredecessor(invoke); +// } +// invoke.successors().clearAll(); + invoke.inputs().clearAll(); + invoke.setExceptionEdge(null); +// invoke.delete(); + + + if (exceptionEdge != null) { + if (unwindNode != null) { + assert unwindNode.predecessors().size() == 1; + assert exceptionEdge.successors().size() == 1; + ExceptionObject obj = (ExceptionObject) exceptionEdge; + + List<Node> usages = new ArrayList<Node>(obj.usages()); + for (Node usage : usages) { + if (replacements.containsKey(unwindNode.exception())) { + usage.inputs().replace(obj, replacements.get(unwindNode.exception())); + } else { + usage.inputs().replace(obj, duplicates.get(unwindNode.exception())); + } + } + Node unwindDuplicate = duplicates.get(unwindNode); + unwindDuplicate.inputs().clearAll(); + + assert unwindDuplicate.predecessors().size() == 1; + Node unwindPred = unwindDuplicate.predecessors().get(0); + int index = unwindDuplicate.predecessorsIndex().get(0); + unwindPred.successors().setAndClear(index, obj, 0); + + obj.inputs().clearAll(); + obj.delete(); + unwindDuplicate.delete(); + + } + } + + // adjust all frame states that were copied + if (frameStates.size() > 0) { + FrameState outerFrameState = stateAfter.duplicateModified(invoke.bci, invoke.kind); + for (Node frameState : frameStates) { + ((FrameState) duplicates.get(frameState)).setOuterFrameState(outerFrameState); + } + } + + if (C1XOptions.TraceInlining) { + ir.verifyAndPrint("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false)); + } + } +}